diff --git a/Minecraft.Client/ClientConnection.cpp b/Minecraft.Client/ClientConnection.cpp index b80eaed..628b330 100644 --- a/Minecraft.Client/ClientConnection.cpp +++ b/Minecraft.Client/ClientConnection.cpp @@ -52,6 +52,11 @@ #endif #include "DLCTexturePack.h" +#ifdef _WINDOWS64 +#include "Xbox\Network\NetworkPlayerXbox.h" +#include "Common\Network\PlatformNetworkManagerStub.h" +#endif + #ifdef _DURANGO #include "..\Minecraft.World\DurangoStats.h" #include "..\Minecraft.World\GenericStats.h" @@ -758,6 +763,27 @@ void ClientConnection::handleAddPlayer(shared_ptr packet) player->displayName = player->name; #endif +#ifdef _WINDOWS64 + { + PlayerUID pktXuid = player->getXuid(); + const PlayerUID WIN64_XUID_BASE = (PlayerUID)0xe000d45248242f2e; + if (pktXuid >= WIN64_XUID_BASE && pktXuid < WIN64_XUID_BASE + MINECRAFT_NET_MAX_PLAYERS) + { + BYTE smallId = (BYTE)(pktXuid - WIN64_XUID_BASE); + INetworkPlayer *np = g_NetworkManager.GetPlayerBySmallId(smallId); + if (np != NULL) + { + NetworkPlayerXbox *npx = (NetworkPlayerXbox *)np; + IQNetPlayer *qp = npx->GetQNetPlayer(); + if (qp != NULL && qp->m_gamertag[0] == 0) + { + wcsncpy_s(qp->m_gamertag, 32, packet->name.c_str(), _TRUNCATE); + } + } + } + } +#endif + // printf("\t\t\t\t%d: Add player\n",packet->id,packet->yRot); int item = packet->carriedItem; @@ -893,6 +919,39 @@ void ClientConnection::handleMoveEntitySmall(shared_ptr p void ClientConnection::handleRemoveEntity(shared_ptr packet) { +#ifdef _WINDOWS64 + if (!g_NetworkManager.IsHost()) + { + for (int i = 0; i < packet->ids.length; i++) + { + shared_ptr entity = getEntity(packet->ids[i]); + if (entity != NULL && entity->GetType() == eTYPE_PLAYER) + { + shared_ptr player = dynamic_pointer_cast(entity); + if (player != NULL) + { + PlayerUID xuid = player->getXuid(); + INetworkPlayer *np = g_NetworkManager.GetPlayerByXuid(xuid); + if (np != NULL) + { + NetworkPlayerXbox *npx = (NetworkPlayerXbox *)np; + IQNetPlayer *qp = npx->GetQNetPlayer(); + if (qp != NULL) + { + extern CPlatformNetworkManagerStub *g_pPlatformNetworkManager; + g_pPlatformNetworkManager->NotifyPlayerLeaving(qp); + qp->m_smallId = 0; + qp->m_isRemote = false; + qp->m_isHostPlayer = false; + qp->m_gamertag[0] = 0; + qp->SetCustomDataValue(0); + } + } + } + } + } + } +#endif for (int i = 0; i < packet->ids.length; i++) { level->removeEntity(packet->ids[i]); diff --git a/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp index 24d5243..0a69cd6 100644 --- a/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp +++ b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp @@ -240,6 +240,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); + } } #endif } @@ -811,7 +833,21 @@ 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); +#ifdef _WINDOWS64 + if (networkPlayer == NULL && smallId != 0 && !m_pIQNet->IsHost()) + { + qnetPlayer->m_isRemote = true; + qnetPlayer->m_isHostPlayer = false; + NotifyPlayerJoined(qnetPlayer); + networkPlayer = getNetworkPlayer(qnetPlayer); + } +#endif + return networkPlayer; } INetworkPlayer *CPlatformNetworkManagerStub::GetHostPlayer() diff --git a/Minecraft.Client/Extrax64Stubs.cpp b/Minecraft.Client/Extrax64Stubs.cpp index 4ebd89e..9db5776 100644 --- a/Minecraft.Client/Extrax64Stubs.cpp +++ b/Minecraft.Client/Extrax64Stubs.cpp @@ -168,7 +168,7 @@ void PIXSetMarkerDeprecated(int a, char *b, ...) {} bool IsEqualXUID(PlayerUID a, PlayerUID b) { -#if defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__) || defined(_DURANGO) +#if defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__) || defined(_DURANGO) || defined(_WINDOWS64) return (a == b); #else return false; @@ -232,13 +232,17 @@ void Win64_SetupRemoteQNetPlayer(IQNetPlayer *player, BYTE smallId, bool isHost, IQNet::s_playerCount = smallId + 1; } +static bool Win64_IsActivePlayer(IQNetPlayer *p, DWORD index); + HRESULT IQNet::AddLocalPlayerByUserIndex(DWORD dwUserIndex){ return S_OK; } IQNetPlayer *IQNet::GetHostPlayer() { return &m_player[0]; } IQNetPlayer *IQNet::GetLocalPlayerByUserIndex(DWORD dwUserIndex) { if (s_isHosting) { - if (dwUserIndex < MINECRAFT_NET_MAX_PLAYERS && !m_player[dwUserIndex].m_isRemote) + if (dwUserIndex < MINECRAFT_NET_MAX_PLAYERS && + !m_player[dwUserIndex].m_isRemote && + Win64_IsActivePlayer(&m_player[dwUserIndex], dwUserIndex)) return &m_player[dwUserIndex]; return NULL; } @@ -246,7 +250,7 @@ IQNetPlayer *IQNet::GetLocalPlayerByUserIndex(DWORD dwUserIndex) return NULL; for (DWORD i = 0; i < s_playerCount; i++) { - if (!m_player[i].m_isRemote) + if (!m_player[i].m_isRemote && Win64_IsActivePlayer(&m_player[i], i)) return &m_player[i]; } return NULL; @@ -272,19 +276,21 @@ IQNetPlayer *IQNet::GetPlayerByIndex(DWORD dwPlayerIndex) } IQNetPlayer *IQNet::GetPlayerBySmallId(BYTE SmallId) { - for (DWORD i = 0; i < s_playerCount; i++) - { - if (m_player[i].m_smallId == SmallId && Win64_IsActivePlayer(&m_player[i], i)) return &m_player[i]; - } - return NULL; + if (SmallId >= MINECRAFT_NET_MAX_PLAYERS) + return NULL; + + m_player[SmallId].m_smallId = SmallId; + if (SmallId >= s_playerCount) + s_playerCount = SmallId + 1; + return &m_player[SmallId]; } IQNetPlayer *IQNet::GetPlayerByXuid(PlayerUID xuid) { - for (DWORD i = 0; i < s_playerCount; i++) + for (DWORD i = 0; i < MINECRAFT_NET_MAX_PLAYERS; i++) { if (Win64_IsActivePlayer(&m_player[i], i) && m_player[i].GetXuid() == xuid) return &m_player[i]; } - return &m_player[0]; + return NULL; } DWORD IQNet::GetPlayerCount() { @@ -299,15 +305,28 @@ QNET_STATE IQNet::GetState() { return _iQNetStubState; } bool IQNet::IsHost() { return s_isHosting; } HRESULT IQNet::JoinGameFromInviteInfo(DWORD dwUserIndex, DWORD dwUserMask, const INVITE_INFO *pInviteInfo) { return S_OK; } void IQNet::HostGame() { _iQNetStubState = QNET_STATE_SESSION_STARTING; s_isHosting = true; } -void IQNet::ClientJoinGame() { _iQNetStubState = QNET_STATE_SESSION_STARTING; s_isHosting = false; } +void IQNet::ClientJoinGame() +{ + _iQNetStubState = QNET_STATE_SESSION_STARTING; + s_isHosting = false; + + for (int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; i++) + { + m_player[i].m_smallId = (BYTE)i; + m_player[i].m_isRemote = true; + m_player[i].m_isHostPlayer = false; + m_player[i].m_gamertag[0] = 0; + m_player[i].SetCustomDataValue(0); + } +} void IQNet::EndGame() { _iQNetStubState = QNET_STATE_IDLE; s_isHosting = false; s_playerCount = 1; - for (int i = 1; i < MINECRAFT_NET_MAX_PLAYERS; i++) + for (int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; i++) { - m_player[i].m_smallId = 0; + m_player[i].m_smallId = (BYTE)i; m_player[i].m_isRemote = false; m_player[i].m_isHostPlayer = false; m_player[i].m_gamertag[0] = 0; diff --git a/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp b/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp index 19fc259..7e7c6ae 100644 --- a/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp +++ b/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp @@ -213,6 +213,14 @@ bool WinsockNetLayer::JoinGame(const char *ip, int port) s_isHost = false; s_hostSmallId = 0; + s_connected = false; + s_active = false; + + if (s_hostConnectionSocket != INVALID_SOCKET) + { + closesocket(s_hostConnectionSocket); + s_hostConnectionSocket = INVALID_SOCKET; + } struct addrinfo hints = {}; struct addrinfo *result = NULL; @@ -231,37 +239,55 @@ 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; + const int maxAttempts = 12; + + 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)); + + iResult = connect(s_hostConnectionSocket, result->ai_addr, (int)result->ai_addrlen); + if (iResult == SOCKET_ERROR) + { + int err = WSAGetLastError(); + 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; + Sleep(200); + continue; + } + + 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; + Sleep(200); + 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) - { - app.DebugPrintf("connect() to %s:%d failed: %d\n", ip, port, WSAGetLastError()); - closesocket(s_hostConnectionSocket); - s_hostConnectionSocket = INVALID_SOCKET; - return false; - } - 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); @@ -479,7 +505,8 @@ DWORD WINAPI WinsockNetLayer::RecvThreadProc(LPVOID param) BYTE clientSmallId = s_connections[connIdx].smallId; LeaveCriticalSection(&s_connectionsLock); - BYTE *recvBuf = new BYTE[WIN64_NET_RECV_BUFFER_SIZE]; + std::vector recvBuf; + recvBuf.resize(WIN64_NET_RECV_BUFFER_SIZE); while (s_active) { @@ -490,33 +517,47 @@ DWORD WINAPI 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("Win64 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) + { + recvBuf.resize(packetSize); + app.DebugPrintf("Win64 LAN: Resized host recv buffer to %d bytes for client smallId=%d\n", packetSize, clientSmallId); + } + + if (!RecvExact(sock, &recvBuf[0], packetSize)) { app.DebugPrintf("Win64 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; } } @@ -550,9 +591,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); +} + DWORD WINAPI WinsockNetLayer::ClientRecvThreadProc(LPVOID param) { - BYTE *recvBuf = new BYTE[WIN64_NET_RECV_BUFFER_SIZE]; + std::vector recvBuf; + recvBuf.resize(WIN64_NET_RECV_BUFFER_SIZE); while (s_active && s_hostConnectionSocket != INVALID_SOCKET) { @@ -565,23 +623,29 @@ DWORD WINAPI WinsockNetLayer::ClientRecvThreadProc(LPVOID param) 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("Win64 LAN: Invalid packet size %d from host (max=%d)\n", + packetSize, + (int)WIN64_NET_MAX_PACKET_SIZE); break; } - if (!RecvExact(s_hostConnectionSocket, recvBuf, packetSize)) + if ((int)recvBuf.size() < packetSize) + { + recvBuf.resize(packetSize); + app.DebugPrintf("Win64 LAN: Resized client recv buffer to %d bytes\n", packetSize); + } + + if (!RecvExact(s_hostConnectionSocket, &recvBuf[0], packetSize)) { app.DebugPrintf("Win64 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; } diff --git a/Minecraft.Client/Windows64/Network/WinsockNetLayer.h b/Minecraft.Client/Windows64/Network/WinsockNetLayer.h index 96b03c9..e6ace42 100644 --- a/Minecraft.Client/Windows64/Network/WinsockNetLayer.h +++ b/Minecraft.Client/Windows64/Network/WinsockNetLayer.h @@ -12,6 +12,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 @@ -81,6 +82,7 @@ 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();