forked from cafeberry/cafeberry
update lcemp networking
This commit is contained in:
@@ -1502,7 +1502,10 @@ void CGameNetworkManager::CreateSocket( INetworkPlayer *pNetworkPlayer, bool loc
|
||||
Minecraft *pMinecraft = Minecraft::GetInstance();
|
||||
|
||||
Socket *socket = NULL;
|
||||
shared_ptr<MultiplayerLocalPlayer> mpPlayer = pMinecraft->localplayers[pNetworkPlayer->GetUserIndex()];
|
||||
shared_ptr<MultiplayerLocalPlayer> mpPlayer = nullptr;
|
||||
int userIdx = pNetworkPlayer->GetUserIndex();
|
||||
if (userIdx >= 0 && userIdx < XUSER_MAX_COUNT)
|
||||
mpPlayer = pMinecraft->localplayers[userIdx];
|
||||
if( localPlayer && mpPlayer != NULL && mpPlayer->connection != NULL)
|
||||
{
|
||||
// If we already have a MultiplayerLocalPlayer here then we are doing a session type change
|
||||
|
||||
@@ -94,7 +94,7 @@ void CPlatformNetworkManagerStub::NotifyPlayerJoined(IQNetPlayer *pQNetPlayer )
|
||||
if( m_pIQNet->IsHost() )
|
||||
{
|
||||
// 4J-PB - only the host should do this
|
||||
// g_NetworkManager.UpdateAndSetGameSessionData();
|
||||
g_NetworkManager.UpdateAndSetGameSessionData();
|
||||
SystemFlagAddPlayer( networkPlayer );
|
||||
}
|
||||
|
||||
@@ -141,6 +141,11 @@ void CPlatformNetworkManagerStub::NotifyPlayerLeaving(IQNetPlayer *pQNetPlayer)
|
||||
|
||||
g_NetworkManager.PlayerLeaving(networkPlayer);
|
||||
|
||||
if (m_pIQNet->IsHost())
|
||||
{
|
||||
g_NetworkManager.UpdateAndSetGameSessionData(networkPlayer);
|
||||
}
|
||||
|
||||
for (int idx = 0; idx < XUSER_MAX_COUNT; ++idx)
|
||||
{
|
||||
if (playerChangedCallback[idx] != NULL)
|
||||
@@ -239,6 +244,28 @@ void CPlatformNetworkManagerStub::DoWork()
|
||||
IQNet::s_playerCount--;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 1; i < MINECRAFT_NET_MAX_PLAYERS; i++)
|
||||
{
|
||||
IQNetPlayer *qp = &IQNet::m_player[i];
|
||||
if (qp->GetCustomDataValue() == 0)
|
||||
continue;
|
||||
INetworkPlayer *np = (INetworkPlayer *)qp->GetCustomDataValue();
|
||||
Socket *sock = np->GetSocket();
|
||||
if (sock != NULL && sock->isClosing())
|
||||
{
|
||||
WinsockNetLayer::CloseConnectionBySmallId((BYTE)i);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_iQNetStubState == QNET_STATE_GAME_PLAY && !m_pIQNet->IsHost())
|
||||
{
|
||||
if (!WinsockNetLayer::IsConnected() && !g_NetworkManager.IsLeavingGame())
|
||||
{
|
||||
if (app.GetDisconnectReason() == DisconnectPacket::eDisconnect_None)
|
||||
app.SetDisconnectReason(DisconnectPacket::eDisconnect_Quitting);
|
||||
app.SetAction(ProfileManager.GetPrimaryPad(), eAppAction_ExitWorld, (void *)TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -470,44 +497,48 @@ bool CPlatformNetworkManagerStub::_RunNetworkGame()
|
||||
|
||||
void CPlatformNetworkManagerStub::UpdateAndSetGameSessionData(INetworkPlayer *pNetworkPlayerLeaving /*= NULL*/)
|
||||
{
|
||||
// DWORD playerCount = m_pIQNet->GetPlayerCount();
|
||||
//
|
||||
// if( this->m_bLeavingGame )
|
||||
// return;
|
||||
//
|
||||
// if( GetHostPlayer() == NULL )
|
||||
// return;
|
||||
//
|
||||
// for(unsigned int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; ++i)
|
||||
// {
|
||||
// if( i < playerCount )
|
||||
// {
|
||||
// INetworkPlayer *pNetworkPlayer = GetPlayerByIndex(i);
|
||||
//
|
||||
// // We can call this from NotifyPlayerLeaving but at that point the player is still considered in the session
|
||||
// if( pNetworkPlayer != pNetworkPlayerLeaving )
|
||||
// {
|
||||
// m_hostGameSessionData.players[i] = ((NetworkPlayerXbox *)pNetworkPlayer)->GetUID();
|
||||
//
|
||||
// char *temp;
|
||||
// temp = (char *)wstringtofilename( pNetworkPlayer->GetOnlineName() );
|
||||
// memcpy(m_hostGameSessionData.szPlayers[i],temp,XUSER_NAME_SIZE);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// m_hostGameSessionData.players[i] = NULL;
|
||||
// memset(m_hostGameSessionData.szPlayers[i],0,XUSER_NAME_SIZE);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// m_hostGameSessionData.players[i] = NULL;
|
||||
// memset(m_hostGameSessionData.szPlayers[i],0,XUSER_NAME_SIZE);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// m_hostGameSessionData.hostPlayerUID = ((NetworkPlayerXbox *)GetHostPlayer())->GetQNetPlayer()->GetXuid();
|
||||
// m_hostGameSessionData.m_uiGameHostSettings = app.GetGameHostOption(eGameHostOption_All);
|
||||
if (this->m_bLeavingGame)
|
||||
return;
|
||||
|
||||
if (!m_pIQNet->IsHost())
|
||||
return;
|
||||
|
||||
DWORD playerCount = m_pIQNet->GetPlayerCount();
|
||||
|
||||
m_hostGameSessionData.m_uiGameHostSettings = app.GetGameHostOption(eGameHostOption_All);
|
||||
m_hostGameSessionData.playerCount = (unsigned char)playerCount;
|
||||
|
||||
for (unsigned int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; ++i)
|
||||
{
|
||||
if (i < playerCount)
|
||||
{
|
||||
INetworkPlayer *pNetworkPlayer = GetPlayerByIndex(i);
|
||||
|
||||
if (pNetworkPlayer != NULL && pNetworkPlayer != pNetworkPlayerLeaving)
|
||||
{
|
||||
m_hostGameSessionData.players[i] = (GameSessionUID)(i + 1);
|
||||
|
||||
const wchar_t *name = pNetworkPlayer->GetOnlineName();
|
||||
char nameBuf[XUSER_NAME_SIZE];
|
||||
memset(nameBuf, 0, sizeof(nameBuf));
|
||||
wcstombs(nameBuf, name, XUSER_NAME_SIZE - 1);
|
||||
memcpy(m_hostGameSessionData.szPlayers[i], nameBuf, XUSER_NAME_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_hostGameSessionData.players[i] = 0;
|
||||
memset(m_hostGameSessionData.szPlayers[i], 0, XUSER_NAME_SIZE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_hostGameSessionData.players[i] = 0;
|
||||
memset(m_hostGameSessionData.szPlayers[i], 0, XUSER_NAME_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
// update the LAN advertiser with current player names and count
|
||||
WinsockNetLayer::UpdateAdvertisePlayerNames(m_hostGameSessionData.playerCount, m_hostGameSessionData.szPlayers);
|
||||
}
|
||||
|
||||
int CPlatformNetworkManagerStub::RemovePlayerOnSocketClosedThreadProc( void* lpParam )
|
||||
@@ -728,6 +759,17 @@ void CPlatformNetworkManagerStub::SearchForGames()
|
||||
info->data.playerCount = lanSessions[i].playerCount;
|
||||
info->data.maxPlayers = lanSessions[i].maxPlayers;
|
||||
|
||||
memset(info->data.players, 0, sizeof(info->data.players));
|
||||
memset(info->data.szPlayers, 0, sizeof(info->data.szPlayers));
|
||||
for (int p = 0; p < MINECRAFT_NET_MAX_PLAYERS && p < lanSessions[i].playerCount; p++)
|
||||
{
|
||||
if (lanSessions[i].playerNames[p][0] != 0)
|
||||
{
|
||||
info->data.players[p] = (GameSessionUID)(p + 1);
|
||||
memcpy(info->data.szPlayers[p], lanSessions[i].playerNames[p], XUSER_NAME_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
info->sessionId = (ULONGLONG)((unsigned __int64)inet_addr(lanSessions[i].hostIP) | ((unsigned __int64)lanSessions[i].hostPort << 32));
|
||||
|
||||
friendsSessions[0].push_back(info);
|
||||
@@ -760,7 +802,19 @@ vector<FriendSessionInfo *> *CPlatformNetworkManagerStub::GetSessionList(int iPa
|
||||
|
||||
bool CPlatformNetworkManagerStub::GetGameSessionInfo(int iPad, SessionID sessionId, FriendSessionInfo *foundSessionInfo)
|
||||
{
|
||||
return false;
|
||||
for (size_t i = 0; i < friendsSessions[0].size(); i++)
|
||||
{
|
||||
if (friendsSessions[0][i]->sessionId == sessionId)
|
||||
{
|
||||
if (foundSessionInfo != NULL)
|
||||
{
|
||||
foundSessionInfo->sessionId = friendsSessions[0][i]->sessionId;
|
||||
foundSessionInfo->data = friendsSessions[0][i]->data;
|
||||
foundSessionInfo->hasPartyMember = friendsSessions[0][i]->hasPartyMember;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CPlatformNetworkManagerStub::SetSessionsUpdatedCallback( void (*SessionsUpdatedCallback)(LPVOID pParam), LPVOID pSearchParam )
|
||||
@@ -830,7 +884,19 @@ INetworkPlayer * CPlatformNetworkManagerStub::GetPlayerByXuid(PlayerUID xuid)
|
||||
|
||||
INetworkPlayer * CPlatformNetworkManagerStub::GetPlayerBySmallId(unsigned char smallId)
|
||||
{
|
||||
return getNetworkPlayer(m_pIQNet->GetPlayerBySmallId(smallId));
|
||||
IQNetPlayer *qnetPlayer = m_pIQNet->GetPlayerBySmallId(smallId);
|
||||
if (qnetPlayer == NULL)
|
||||
return NULL;
|
||||
|
||||
INetworkPlayer *networkPlayer = getNetworkPlayer(qnetPlayer);
|
||||
if (networkPlayer == NULL && smallId != 0 && !m_pIQNet->IsHost())
|
||||
{
|
||||
qnetPlayer->m_isRemote = true;
|
||||
qnetPlayer->m_isHostPlayer = false;
|
||||
NotifyPlayerJoined(qnetPlayer);
|
||||
networkPlayer = getNetworkPlayer(qnetPlayer);
|
||||
}
|
||||
return networkPlayer;
|
||||
}
|
||||
|
||||
INetworkPlayer *CPlatformNetworkManagerStub::GetHostPlayer()
|
||||
|
||||
@@ -86,6 +86,9 @@ typedef struct _GameSessionData
|
||||
unsigned char playerCount; // 1 byte
|
||||
unsigned char maxPlayers; // 1 byte
|
||||
|
||||
GameSessionUID players[MINECRAFT_NET_MAX_PLAYERS];
|
||||
char szPlayers[MINECRAFT_NET_MAX_PLAYERS][XUSER_NAME_SIZE];
|
||||
|
||||
_GameSessionData()
|
||||
{
|
||||
netVersion = 0;
|
||||
@@ -99,6 +102,8 @@ typedef struct _GameSessionData
|
||||
memset(hostName, 0, sizeof(hostName));
|
||||
playerCount = 0;
|
||||
maxPlayers = MINECRAFT_NET_MAX_PLAYERS;
|
||||
memset(players, 0, sizeof(players));
|
||||
memset(szPlayers, 0, sizeof(szPlayers));
|
||||
}
|
||||
} GameSessionData;
|
||||
#endif
|
||||
|
||||
@@ -321,8 +321,18 @@ bool WinsockNetLayer::JoinGame(const char *ip, int port)
|
||||
|
||||
s_isHost = false;
|
||||
s_hostSmallId = 0;
|
||||
s_connected = false;
|
||||
s_active = false;
|
||||
|
||||
const int maxAttempts = 3;
|
||||
const int connectTimeoutMs = 3000;
|
||||
#if defined _WINDOWS64
|
||||
if (s_hostConnectionSocket != INVALID_SOCKET)
|
||||
{
|
||||
closesocket(s_hostConnectionSocket);
|
||||
s_hostConnectionSocket = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
struct addrinfo hints = {};
|
||||
struct addrinfo *result = NULL;
|
||||
|
||||
@@ -340,27 +350,97 @@ bool WinsockNetLayer::JoinGame(const char *ip, int port)
|
||||
return false;
|
||||
}
|
||||
|
||||
s_hostConnectionSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
|
||||
if (s_hostConnectionSocket == INVALID_SOCKET)
|
||||
bool connected = false;
|
||||
BYTE assignedSmallId = 0;
|
||||
|
||||
for (int attempt = 0; attempt < maxAttempts; ++attempt)
|
||||
{
|
||||
app.DebugPrintf("socket() failed: %d\n", WSAGetLastError());
|
||||
freeaddrinfo(result);
|
||||
return false;
|
||||
s_hostConnectionSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
|
||||
if (s_hostConnectionSocket == INVALID_SOCKET)
|
||||
{
|
||||
app.DebugPrintf("socket() failed: %d\n", WSAGetLastError());
|
||||
break;
|
||||
}
|
||||
|
||||
int noDelay = 1;
|
||||
setsockopt(s_hostConnectionSocket, IPPROTO_TCP, TCP_NODELAY, (const char *)&noDelay, sizeof(noDelay));
|
||||
|
||||
u_long nonBlocking = 1;
|
||||
ioctlsocket(s_hostConnectionSocket, FIONBIO, &nonBlocking);
|
||||
|
||||
iResult = connect(s_hostConnectionSocket, result->ai_addr, (int)result->ai_addrlen);
|
||||
if (iResult == SOCKET_ERROR)
|
||||
{
|
||||
int err = WSAGetLastError();
|
||||
if (err == WSAEWOULDBLOCK)
|
||||
{
|
||||
fd_set writeFds, exceptFds;
|
||||
FD_ZERO(&writeFds);
|
||||
FD_ZERO(&exceptFds);
|
||||
FD_SET(s_hostConnectionSocket, &writeFds);
|
||||
FD_SET(s_hostConnectionSocket, &exceptFds);
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = connectTimeoutMs / 1000;
|
||||
tv.tv_usec = (connectTimeoutMs % 1000) * 1000;
|
||||
|
||||
int selectResult = select(0, NULL, &writeFds, &exceptFds, &tv);
|
||||
if (selectResult <= 0 || FD_ISSET(s_hostConnectionSocket, &exceptFds))
|
||||
{
|
||||
app.DebugPrintf("connect() to %s:%d timed out or failed (attempt %d/%d)\n", ip, port, attempt + 1, maxAttempts);
|
||||
closesocket(s_hostConnectionSocket);
|
||||
s_hostConnectionSocket = INVALID_SOCKET;
|
||||
continue;
|
||||
}
|
||||
|
||||
int sockErr = 0;
|
||||
int sockErrLen = sizeof(sockErr);
|
||||
getsockopt(s_hostConnectionSocket, SOL_SOCKET, SO_ERROR, (char *)&sockErr, &sockErrLen);
|
||||
if (sockErr != 0)
|
||||
{
|
||||
app.DebugPrintf("connect() to %s:%d failed with SO_ERROR %d (attempt %d/%d)\n", ip, port, sockErr, attempt + 1, maxAttempts);
|
||||
closesocket(s_hostConnectionSocket);
|
||||
s_hostConnectionSocket = INVALID_SOCKET;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
app.DebugPrintf("connect() to %s:%d failed (attempt %d/%d): %d\n", ip, port, attempt + 1, maxAttempts, err);
|
||||
closesocket(s_hostConnectionSocket);
|
||||
s_hostConnectionSocket = INVALID_SOCKET;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
u_long blocking = 0;
|
||||
ioctlsocket(s_hostConnectionSocket, FIONBIO, &blocking);
|
||||
|
||||
DWORD recvTimeout = 3000;
|
||||
setsockopt(s_hostConnectionSocket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&recvTimeout, sizeof(recvTimeout));
|
||||
|
||||
BYTE assignBuf[1];
|
||||
int bytesRecv = recv(s_hostConnectionSocket, (char *)assignBuf, 1, 0);
|
||||
if (bytesRecv != 1)
|
||||
{
|
||||
app.DebugPrintf("Failed to receive small ID assignment from host (attempt %d/%d)\n", attempt + 1, maxAttempts);
|
||||
closesocket(s_hostConnectionSocket);
|
||||
s_hostConnectionSocket = INVALID_SOCKET;
|
||||
continue;
|
||||
}
|
||||
|
||||
assignedSmallId = assignBuf[0];
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
|
||||
int noDelay = 1;
|
||||
setsockopt(s_hostConnectionSocket, IPPROTO_TCP, TCP_NODELAY, (const char *)&noDelay, sizeof(noDelay));
|
||||
|
||||
iResult = connect(s_hostConnectionSocket, result->ai_addr, (int)result->ai_addrlen);
|
||||
freeaddrinfo(result);
|
||||
if (iResult == SOCKET_ERROR)
|
||||
#elif defined _XBOX
|
||||
if (s_hostConnectionSocket != INVALID_SOCKET)
|
||||
{
|
||||
app.DebugPrintf("connect() to %s:%d failed: %d\n", ip, port, WSAGetLastError());
|
||||
closesocket(s_hostConnectionSocket);
|
||||
s_hostConnectionSocket = INVALID_SOCKET;
|
||||
return false;
|
||||
}
|
||||
#elif defined _XBOX
|
||||
|
||||
XNDNS *pDns = NULL;
|
||||
int iResult = XNetDnsLookup(ip, NULL, &pDns);
|
||||
if (iResult != 0 || pDns == NULL)
|
||||
@@ -387,25 +467,85 @@ bool WinsockNetLayer::JoinGame(const char *ip, int port)
|
||||
addr.sin_addr = pDns->aina[0];
|
||||
XNetDnsRelease(pDns);
|
||||
|
||||
s_hostConnectionSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (s_hostConnectionSocket == INVALID_SOCKET)
|
||||
{
|
||||
app.DebugPrintf("socket() failed: %d\n", WSAGetLastError());
|
||||
return false;
|
||||
}
|
||||
bool connected = false;
|
||||
BYTE assignedSmallId = 0;
|
||||
|
||||
int noDelay = 1;
|
||||
setsockopt(s_hostConnectionSocket, IPPROTO_TCP, TCP_NODELAY, (const char *)&noDelay, sizeof(noDelay));
|
||||
|
||||
iResult = connect(s_hostConnectionSocket, (struct sockaddr*)&addr, sizeof(addr));
|
||||
if (iResult == SOCKET_ERROR)
|
||||
for (int attempt = 0; attempt < maxAttempts; ++attempt)
|
||||
{
|
||||
app.DebugPrintf("connect() to %s:%d failed: %d\n", ip, port, WSAGetLastError());
|
||||
closesocket(s_hostConnectionSocket);
|
||||
s_hostConnectionSocket = INVALID_SOCKET;
|
||||
return false;
|
||||
s_hostConnectionSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (s_hostConnectionSocket == INVALID_SOCKET)
|
||||
{
|
||||
app.DebugPrintf("socket() failed: %d\n", WSAGetLastError());
|
||||
break;
|
||||
}
|
||||
|
||||
int noDelay = 1;
|
||||
setsockopt(s_hostConnectionSocket, IPPROTO_TCP, TCP_NODELAY, (const char *)&noDelay, sizeof(noDelay));
|
||||
|
||||
u_long nonBlocking = 1;
|
||||
ioctlsocket(s_hostConnectionSocket, FIONBIO, &nonBlocking);
|
||||
|
||||
iResult = connect(s_hostConnectionSocket, (struct sockaddr*)&addr, sizeof(addr));
|
||||
if (iResult == SOCKET_ERROR)
|
||||
{
|
||||
int err = WSAGetLastError();
|
||||
if (err == WSAEWOULDBLOCK)
|
||||
{
|
||||
fd_set writeFds, exceptFds;
|
||||
FD_ZERO(&writeFds);
|
||||
FD_ZERO(&exceptFds);
|
||||
FD_SET(s_hostConnectionSocket, &writeFds);
|
||||
FD_SET(s_hostConnectionSocket, &exceptFds);
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = connectTimeoutMs / 1000;
|
||||
tv.tv_usec = (connectTimeoutMs % 1000) * 1000;
|
||||
|
||||
int selectResult = select(0, NULL, &writeFds, &exceptFds, &tv);
|
||||
if (selectResult <= 0 || FD_ISSET(s_hostConnectionSocket, &exceptFds))
|
||||
{
|
||||
app.DebugPrintf("connect() to %s:%d timed out or failed (attempt %d/%d)\n", ip, port, attempt + 1, maxAttempts);
|
||||
closesocket(s_hostConnectionSocket);
|
||||
s_hostConnectionSocket = INVALID_SOCKET;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
app.DebugPrintf("connect() to %s:%d failed (attempt %d/%d): %d\n", ip, port, attempt + 1, maxAttempts, err);
|
||||
closesocket(s_hostConnectionSocket);
|
||||
s_hostConnectionSocket = INVALID_SOCKET;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
u_long blocking = 0;
|
||||
ioctlsocket(s_hostConnectionSocket, FIONBIO, &blocking);
|
||||
|
||||
DWORD recvTimeout = 3000;
|
||||
setsockopt(s_hostConnectionSocket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&recvTimeout, sizeof(recvTimeout));
|
||||
|
||||
BYTE assignBuf[1];
|
||||
int bytesRecv = recv(s_hostConnectionSocket, (char *)assignBuf, 1, 0);
|
||||
if (bytesRecv != 1)
|
||||
{
|
||||
app.DebugPrintf("Failed to receive small ID assignment from host (attempt %d/%d)\n", attempt + 1, maxAttempts);
|
||||
closesocket(s_hostConnectionSocket);
|
||||
s_hostConnectionSocket = INVALID_SOCKET;
|
||||
continue;
|
||||
}
|
||||
|
||||
assignedSmallId = assignBuf[0];
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
#elif defined __PS3__
|
||||
if (s_hostConnectionSocket != -1)
|
||||
{
|
||||
socketclose(s_hostConnectionSocket);
|
||||
s_hostConnectionSocket = -1;
|
||||
}
|
||||
|
||||
struct sockaddr_in addr = {};
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
@@ -418,38 +558,108 @@ bool WinsockNetLayer::JoinGame(const char *ip, int port)
|
||||
return false;
|
||||
}
|
||||
|
||||
int iResult = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
s_hostConnectionSocket = iResult;
|
||||
if (s_hostConnectionSocket < 0)
|
||||
{
|
||||
app.DebugPrintf("socket() failed: %d\n", s_hostConnectionSocket);
|
||||
return false;
|
||||
}
|
||||
bool connected = false;
|
||||
BYTE assignedSmallId = 0;
|
||||
|
||||
int noDelay = 1;
|
||||
setsockopt(s_hostConnectionSocket, IPPROTO_TCP, TCP_NODELAY, (const char *)&noDelay, sizeof(noDelay));
|
||||
|
||||
iResult = connect(s_hostConnectionSocket, (struct sockaddr*)&addr, sizeof(addr));
|
||||
if (iResult < 0)
|
||||
for (int attempt = 0; attempt < maxAttempts; ++attempt)
|
||||
{
|
||||
app.DebugPrintf("connect() to %s:%d failed: %d\n", ip, port, s_hostConnectionSocket);
|
||||
socketclose(s_hostConnectionSocket);
|
||||
s_hostConnectionSocket = -1;
|
||||
return false;
|
||||
int iResult = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
s_hostConnectionSocket = iResult;
|
||||
if (s_hostConnectionSocket < 0)
|
||||
{
|
||||
app.DebugPrintf("socket() failed: %d\n", s_hostConnectionSocket);
|
||||
break;
|
||||
}
|
||||
|
||||
int noDelay = 1;
|
||||
setsockopt(s_hostConnectionSocket, IPPROTO_TCP, TCP_NODELAY, (const char *)&noDelay, sizeof(noDelay));
|
||||
|
||||
int nonBlocking = 1;
|
||||
setsockopt(s_hostConnectionSocket, SOL_SOCKET, SO_NBIO, &nonBlocking, sizeof(nonBlocking));
|
||||
|
||||
iResult = connect(s_hostConnectionSocket, (struct sockaddr*)&addr, sizeof(addr));
|
||||
if (iResult < 0)
|
||||
{
|
||||
int err = sys_net_errno;
|
||||
if (err == SYS_NET_EINPROGRESS)
|
||||
{
|
||||
fd_set writeFds, exceptFds;
|
||||
FD_ZERO(&writeFds);
|
||||
FD_ZERO(&exceptFds);
|
||||
FD_SET(s_hostConnectionSocket, &writeFds);
|
||||
FD_SET(s_hostConnectionSocket, &exceptFds);
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = connectTimeoutMs / 1000;
|
||||
tv.tv_usec = (connectTimeoutMs % 1000) * 1000;
|
||||
|
||||
int selectResult = socketselect(s_hostConnectionSocket + 1, NULL, &writeFds, &exceptFds, &tv);
|
||||
if (selectResult <= 0 || FD_ISSET(s_hostConnectionSocket, &exceptFds))
|
||||
{
|
||||
app.DebugPrintf("connect() to %s:%d timed out or failed (attempt %d/%d)\n", ip, port, attempt + 1, maxAttempts);
|
||||
closesocket(s_hostConnectionSocket);
|
||||
s_hostConnectionSocket = INVALID_SOCKET;
|
||||
continue;
|
||||
}
|
||||
|
||||
int sockErr = 0;
|
||||
socklen_t sockErrLen = sizeof(sockErr);
|
||||
getsockopt(s_hostConnectionSocket, SOL_SOCKET, SO_ERROR, (char *)&sockErr, &sockErrLen);
|
||||
if (sockErr != 0)
|
||||
{
|
||||
app.DebugPrintf("connect() to %s:%d failed with SO_ERROR %d (attempt %d/%d)\n", ip, port, sockErr, attempt + 1, maxAttempts);
|
||||
closesocket(s_hostConnectionSocket);
|
||||
s_hostConnectionSocket = INVALID_SOCKET;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
app.DebugPrintf("connect() to %s:%d failed (attempt %d/%d): %d\n", ip, port, attempt + 1, maxAttempts, err);
|
||||
closesocket(s_hostConnectionSocket);
|
||||
s_hostConnectionSocket = INVALID_SOCKET;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
int blocking = 0;
|
||||
setsockopt(s_hostConnectionSocket, SOL_SOCKET, SO_NBIO, &blocking, sizeof(blocking));
|
||||
|
||||
DWORD recvTimeout = 3000;
|
||||
setsockopt(s_hostConnectionSocket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&recvTimeout, sizeof(recvTimeout));
|
||||
/*
|
||||
iResult = connect(s_hostConnectionSocket, (struct sockaddr*)&addr, sizeof(addr));
|
||||
if (iResult < 0)
|
||||
{
|
||||
app.DebugPrintf("connect() to %s:%d failed: %d\n", ip, port, s_hostConnectionSocket);
|
||||
socketclose(s_hostConnectionSocket);
|
||||
s_hostConnectionSocket = -1;
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
BYTE assignBuf[1];
|
||||
int bytesRecv = recv(s_hostConnectionSocket, (char *)assignBuf, 1, 0);
|
||||
if (bytesRecv != 1)
|
||||
{
|
||||
app.DebugPrintf("Failed to receive small ID assignment from host (attempt %d/%d)\n", attempt + 1, maxAttempts);
|
||||
closesocket(s_hostConnectionSocket);
|
||||
s_hostConnectionSocket = INVALID_SOCKET;
|
||||
continue;
|
||||
}
|
||||
|
||||
assignedSmallId = assignBuf[0];
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
BYTE assignBuf[1];
|
||||
int bytesRecv = recv(s_hostConnectionSocket, (char *)assignBuf, 1, 0);
|
||||
if (bytesRecv != 1)
|
||||
if (!connected)
|
||||
{
|
||||
app.DebugPrintf("Failed to receive small ID assignment from host\n");
|
||||
closesocket(s_hostConnectionSocket);
|
||||
s_hostConnectionSocket = INVALID_SOCKET;
|
||||
return false;
|
||||
}
|
||||
s_localSmallId = assignBuf[0];
|
||||
s_localSmallId = assignedSmallId;
|
||||
|
||||
app.DebugPrintf("Win64 LAN: Connected to %s:%d, assigned smallId=%d\n", ip, port, s_localSmallId);
|
||||
app.DebugPrintf("LAN: Connected to %s:%d, assigned smallId=%d\n", ip, port, s_localSmallId);
|
||||
|
||||
s_active = true;
|
||||
s_connected = true;
|
||||
@@ -698,7 +908,8 @@ int WinsockNetLayer::RecvThreadProc(LPVOID param)
|
||||
BYTE clientSmallId = s_connections[connIdx].smallId;
|
||||
LeaveCriticalSection(&s_connectionsLock);
|
||||
|
||||
BYTE *recvBuf = new BYTE[WIN64_NET_RECV_BUFFER_SIZE];
|
||||
std::vector<BYTE> recvBuf;
|
||||
recvBuf.resize(WIN64_NET_RECV_BUFFER_SIZE);
|
||||
|
||||
while (s_active)
|
||||
{
|
||||
@@ -709,33 +920,47 @@ int WinsockNetLayer::RecvThreadProc(LPVOID param)
|
||||
break;
|
||||
}
|
||||
|
||||
int packetSize = (header[0] << 24) | (header[1] << 16) | (header[2] << 8) | header[3];
|
||||
int packetSize =
|
||||
((uint32_t)header[0] << 24) |
|
||||
((uint32_t)header[1] << 16) |
|
||||
((uint32_t)header[2] << 8) |
|
||||
((uint32_t)header[3]);
|
||||
|
||||
if (packetSize <= 0 || packetSize > WIN64_NET_RECV_BUFFER_SIZE)
|
||||
if (packetSize <= 0 || packetSize > WIN64_NET_MAX_PACKET_SIZE)
|
||||
{
|
||||
app.DebugPrintf("Win64 LAN: Invalid packet size %d from client smallId=%d\n", packetSize, clientSmallId);
|
||||
app.DebugPrintf("LAN: Invalid packet size %d from client smallId=%d (max=%d)\n",
|
||||
packetSize,
|
||||
clientSmallId,
|
||||
(int)WIN64_NET_MAX_PACKET_SIZE);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!RecvExact(sock, recvBuf, packetSize))
|
||||
if ((int)recvBuf.size() < packetSize)
|
||||
{
|
||||
app.DebugPrintf("Win64 LAN: Client smallId=%d disconnected (body)\n", clientSmallId);
|
||||
recvBuf.resize(packetSize);
|
||||
app.DebugPrintf("LAN: Resized host recv buffer to %d bytes for client smallId=%d\n", packetSize, clientSmallId);
|
||||
}
|
||||
|
||||
if (!RecvExact(sock, &recvBuf[0], packetSize))
|
||||
{
|
||||
app.DebugPrintf("LAN: Client smallId=%d disconnected (body)\n", clientSmallId);
|
||||
break;
|
||||
}
|
||||
|
||||
HandleDataReceived(clientSmallId, s_hostSmallId, recvBuf, packetSize);
|
||||
HandleDataReceived(clientSmallId, s_hostSmallId, &recvBuf[0], packetSize);
|
||||
}
|
||||
|
||||
delete[] recvBuf;
|
||||
|
||||
EnterCriticalSection(&s_connectionsLock);
|
||||
for (size_t i = 0; i < s_connections.size(); i++)
|
||||
{
|
||||
if (s_connections[i].smallId == clientSmallId)
|
||||
{
|
||||
s_connections[i].active = false;
|
||||
closesocket(s_connections[i].tcpSocket);
|
||||
s_connections[i].tcpSocket = INVALID_SOCKET;
|
||||
if (s_connections[i].tcpSocket != INVALID_SOCKET)
|
||||
{
|
||||
closesocket(s_connections[i].tcpSocket);
|
||||
s_connections[i].tcpSocket = INVALID_SOCKET;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -769,9 +994,26 @@ void WinsockNetLayer::PushFreeSmallId(BYTE smallId)
|
||||
LeaveCriticalSection(&s_freeSmallIdLock);
|
||||
}
|
||||
|
||||
void WinsockNetLayer::CloseConnectionBySmallId(BYTE smallId)
|
||||
{
|
||||
EnterCriticalSection(&s_connectionsLock);
|
||||
for (size_t i = 0; i < s_connections.size(); i++)
|
||||
{
|
||||
if (s_connections[i].smallId == smallId && s_connections[i].active && s_connections[i].tcpSocket != INVALID_SOCKET)
|
||||
{
|
||||
closesocket(s_connections[i].tcpSocket);
|
||||
s_connections[i].tcpSocket = INVALID_SOCKET;
|
||||
app.DebugPrintf("Win64 LAN: Force-closed TCP connection for smallId=%d\n", smallId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&s_connectionsLock);
|
||||
}
|
||||
|
||||
int WinsockNetLayer::ClientRecvThreadProc(LPVOID param)
|
||||
{
|
||||
BYTE *recvBuf = new BYTE[WIN64_NET_RECV_BUFFER_SIZE];
|
||||
std::vector<BYTE> recvBuf;
|
||||
recvBuf.resize(WIN64_NET_RECV_BUFFER_SIZE);
|
||||
|
||||
#if defined _WINDOWS64 || defined _XBOX
|
||||
while (s_active && s_hostConnectionSocket != INVALID_SOCKET)
|
||||
@@ -782,29 +1024,33 @@ int WinsockNetLayer::ClientRecvThreadProc(LPVOID param)
|
||||
BYTE header[4];
|
||||
if (!RecvExact(s_hostConnectionSocket, header, 4))
|
||||
{
|
||||
app.DebugPrintf("Win64 LAN: Disconnected from host (header)\n");
|
||||
app.DebugPrintf("LAN: Disconnected from host (header)\n");
|
||||
break;
|
||||
}
|
||||
|
||||
int packetSize = (header[0] << 24) | (header[1] << 16) | (header[2] << 8) | header[3];
|
||||
|
||||
if (packetSize <= 0 || packetSize > WIN64_NET_RECV_BUFFER_SIZE)
|
||||
if (packetSize <= 0 || packetSize > WIN64_NET_MAX_PACKET_SIZE)
|
||||
{
|
||||
app.DebugPrintf("Win64 LAN: Invalid packet size %d from host\n", packetSize);
|
||||
app.DebugPrintf("LAN: Invalid packet size %d from host\n", packetSize);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!RecvExact(s_hostConnectionSocket, recvBuf, packetSize))
|
||||
if ((int)recvBuf.size() < packetSize)
|
||||
{
|
||||
app.DebugPrintf("Win64 LAN: Disconnected from host (body)\n");
|
||||
recvBuf.resize(packetSize);
|
||||
app.DebugPrintf("LAN: Resized client recv buffer to %d bytes\n", packetSize);
|
||||
}
|
||||
|
||||
if (!RecvExact(s_hostConnectionSocket, &recvBuf[0], packetSize))
|
||||
{
|
||||
app.DebugPrintf("LAN: Disconnected from host (body)\n");
|
||||
break;
|
||||
}
|
||||
|
||||
HandleDataReceived(s_hostSmallId, s_localSmallId, recvBuf, packetSize);
|
||||
HandleDataReceived(s_hostSmallId, s_localSmallId, &recvBuf[0], packetSize);
|
||||
}
|
||||
|
||||
delete[] recvBuf;
|
||||
|
||||
s_connected = false;
|
||||
return 0;
|
||||
}
|
||||
@@ -887,6 +1133,18 @@ void WinsockNetLayer::UpdateAdvertisePlayerCount(BYTE count)
|
||||
LeaveCriticalSection(&s_advertiseLock);
|
||||
}
|
||||
|
||||
void WinsockNetLayer::UpdateAdvertisePlayerNames(BYTE count, const char playerNames[][XUSER_NAME_SIZE])
|
||||
{
|
||||
EnterCriticalSection(&s_advertiseLock);
|
||||
memset(s_advertiseData.playerNames, 0, sizeof(s_advertiseData.playerNames));
|
||||
s_advertiseData.playerCount = count;
|
||||
for (int i = 0; i < count && i < 8; i++)
|
||||
{
|
||||
memcpy(s_advertiseData.playerNames[i], playerNames[i], XUSER_NAME_SIZE);
|
||||
}
|
||||
LeaveCriticalSection(&s_advertiseLock);
|
||||
}
|
||||
|
||||
void WinsockNetLayer::UpdateAdvertiseJoinable(bool joinable)
|
||||
{
|
||||
EnterCriticalSection(&s_advertiseLock);
|
||||
@@ -1028,16 +1286,18 @@ void WinsockNetLayer::StopDiscovery()
|
||||
std::vector<Win64LANSession> WinsockNetLayer::GetDiscoveredSessions()
|
||||
{
|
||||
std::vector<Win64LANSession> result;
|
||||
EnterCriticalSection(&s_discoveryLock);
|
||||
result = s_discoveredSessions;
|
||||
LeaveCriticalSection(&s_discoveryLock);
|
||||
if (TryEnterCriticalSection(&s_discoveryLock))
|
||||
{
|
||||
result = s_discoveredSessions;
|
||||
LeaveCriticalSection(&s_discoveryLock);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int WinsockNetLayer::DiscoveryThreadProc(LPVOID param)
|
||||
{
|
||||
app.DebugPrintf("Discovery thread started\n");
|
||||
char recvBuf[512];
|
||||
char recvBuf[1024];
|
||||
|
||||
while (s_discovering)
|
||||
{
|
||||
@@ -1111,6 +1371,7 @@ int WinsockNetLayer::DiscoveryThreadProc(LPVOID param)
|
||||
s_discoveredSessions[i].subTexturePackId = broadcast->subTexturePackId;
|
||||
s_discoveredSessions[i].isJoinable = (broadcast->isJoinable != 0);
|
||||
s_discoveredSessions[i].lastSeenTick = now;
|
||||
memcpy(s_discoveredSessions[i].playerNames, broadcast->playerNames, sizeof(broadcast->playerNames));
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@@ -1137,6 +1398,7 @@ int WinsockNetLayer::DiscoveryThreadProc(LPVOID param)
|
||||
session.subTexturePackId = broadcast->subTexturePackId;
|
||||
session.isJoinable = (broadcast->isJoinable != 0);
|
||||
session.lastSeenTick = now;
|
||||
memcpy(session.playerNames, broadcast->playerNames, sizeof(broadcast->playerNames));
|
||||
s_discoveredSessions.push_back(session);
|
||||
|
||||
app.DebugPrintf("LAN: Discovered game \"%ls\" at %s:%d\n",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <WinSock2.h>
|
||||
#include <WS2tcpip.h>
|
||||
#elif defined _XBOX
|
||||
#include <stdint.h>
|
||||
#include <winsockx.h>
|
||||
#include <xtl.h>
|
||||
#elif defined __PS3__
|
||||
@@ -15,6 +16,8 @@
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
@@ -27,6 +30,7 @@
|
||||
#define WIN64_NET_DEFAULT_PORT 25565
|
||||
#define WIN64_NET_MAX_CLIENTS 7
|
||||
#define WIN64_NET_RECV_BUFFER_SIZE 65536
|
||||
#define WIN64_NET_MAX_PACKET_SIZE (4 * 1024 * 1024)
|
||||
#define WIN64_LAN_DISCOVERY_PORT 25566
|
||||
#define WIN64_LAN_BROADCAST_MAGIC 0x4D434C4E
|
||||
|
||||
@@ -50,6 +54,7 @@ struct Win64LANBroadcast
|
||||
DWORD texturePackParentId;
|
||||
BYTE subTexturePackId;
|
||||
BYTE isJoinable;
|
||||
char playerNames[8][XUSER_NAME_SIZE];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
@@ -66,6 +71,7 @@ struct Win64LANSession
|
||||
unsigned char subTexturePackId;
|
||||
bool isJoinable;
|
||||
DWORD lastSeenTick;
|
||||
char playerNames[8][XUSER_NAME_SIZE];
|
||||
};
|
||||
|
||||
struct Win64RemoteConnection
|
||||
@@ -101,11 +107,13 @@ public:
|
||||
|
||||
static bool PopDisconnectedSmallId(BYTE *outSmallId);
|
||||
static void PushFreeSmallId(BYTE smallId);
|
||||
static void CloseConnectionBySmallId(BYTE smallId);
|
||||
|
||||
static bool StartAdvertising(int gamePort, const wchar_t *hostName, unsigned int gameSettings, unsigned int texPackId, unsigned char subTexId, unsigned short netVer);
|
||||
static void StopAdvertising();
|
||||
static void UpdateAdvertisePlayerCount(BYTE count);
|
||||
static void UpdateAdvertiseJoinable(bool joinable);
|
||||
static void UpdateAdvertisePlayerNames(BYTE count, const char playerNames[][XUSER_NAME_SIZE]);
|
||||
|
||||
static bool StartDiscovery();
|
||||
static void StopDiscovery();
|
||||
|
||||
Reference in New Issue
Block a user