fix: major windows64 net fixes

This commit is contained in:
NOTPIES 2026-03-02 23:10:41 -03:00
parent ecaee55892
commit 7c4b30d11e
5 changed files with 235 additions and 55 deletions

View file

@ -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<AddPlayerPacket> 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<MoveEntityPacketSmall> p
void ClientConnection::handleRemoveEntity(shared_ptr<RemoveEntitiesPacket> packet)
{
#ifdef _WINDOWS64
if (!g_NetworkManager.IsHost())
{
for (int i = 0; i < packet->ids.length; i++)
{
shared_ptr<Entity> entity = getEntity(packet->ids[i]);
if (entity != NULL && entity->GetType() == eTYPE_PLAYER)
{
shared_ptr<Player> player = dynamic_pointer_cast<Player>(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]);

View file

@ -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()

View file

@ -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;

View file

@ -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<BYTE> 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<BYTE> 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;
}

View file

@ -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();