diff options
Diffstat (limited to 'Minecraft.Client/Common/Network')
| -rw-r--r-- | Minecraft.Client/Common/Network/GameNetworkManager.cpp | 44 | ||||
| -rw-r--r-- | Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp | 46 |
2 files changed, 84 insertions, 6 deletions
diff --git a/Minecraft.Client/Common/Network/GameNetworkManager.cpp b/Minecraft.Client/Common/Network/GameNetworkManager.cpp index 92ea8ad0..88db4911 100644 --- a/Minecraft.Client/Common/Network/GameNetworkManager.cpp +++ b/Minecraft.Client/Common/Network/GameNetworkManager.cpp @@ -41,6 +41,11 @@ #include "..\Minecraft.World\DurangoStats.h" #endif +#ifdef _WINDOWS64 +#include "..\..\Windows64\Network\WinsockNetLayer.h" +#include "..\..\Windows64\Windows64_Xuid.h" +#endif + // Global instance CGameNetworkManager g_NetworkManager; CPlatformNetworkManager *CGameNetworkManager::s_pPlatformNetworkManager; @@ -1501,6 +1506,45 @@ void CGameNetworkManager::CreateSocket( INetworkPlayer *pNetworkPlayer, bool loc } else { +#ifdef _WINDOWS64 + // Non-host split-screen: open a dedicated TCP connection for this pad + if (localPlayer && !g_NetworkManager.IsHost() && g_NetworkManager.IsInGameplay()) + { + int padIdx = pNetworkPlayer->GetUserIndex(); + BYTE assignedSmallId = 0; + + if (!WinsockNetLayer::JoinSplitScreen(padIdx, &assignedSmallId)) + { + app.DebugPrintf("Split-screen pad %d: failed to open TCP to host\n", padIdx); + pMinecraft->connectionDisconnected(padIdx, DisconnectPacket::eDisconnect_ConnectionCreationFailed); + return; + } + + // Update the local IQNetPlayer (at pad index) with the host-assigned smallId. + // The NetworkPlayerXbox created by NotifyPlayerJoined already points to + // m_player[padIdx], so we just set the smallId for network routing. + IQNet::m_player[padIdx].m_smallId = assignedSmallId; + IQNet::m_player[padIdx].m_resolvedXuid = Win64Xuid::DeriveXuidForPad(Win64Xuid::ResolvePersistentXuid(), padIdx); + + // Network socket (not hostLocal) — data goes through TCP via GetLocalSocket + socket = new Socket(pNetworkPlayer, false, false); + pNetworkPlayer->SetSocket(socket); + + ClientConnection* connection = new ClientConnection(pMinecraft, socket, padIdx); + if (connection->createdOk) + { + connection->send(shared_ptr<PreLoginPacket>(new PreLoginPacket(pNetworkPlayer->GetOnlineName()))); + pMinecraft->addPendingLocalConnection(padIdx, connection); + } + else + { + pMinecraft->connectionDisconnected(padIdx, DisconnectPacket::eDisconnect_ConnectionCreationFailed); + delete connection; + } + return; + } +#endif + socket = new Socket( pNetworkPlayer, g_NetworkManager.IsHost(), g_NetworkManager.IsHost() && localPlayer ); pNetworkPlayer->SetSocket( socket ); diff --git a/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp index 44ca3c2f..3d088935 100644 --- a/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp +++ b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp @@ -243,10 +243,16 @@ void CPlatformNetworkManagerStub::DoWork() if (IQNet::s_playerCount > 1) IQNet::s_playerCount--; } - // Always return smallId to the free pool so it can be reused (game may have already cleared the slot). - WinsockNetLayer::PushFreeSmallId(disconnectedSmallId); - // Clear O(1) socket lookup so GetSocketForSmallId stays fast (s_connections never shrinks). - WinsockNetLayer::ClearSocketForSmallId(disconnectedSmallId); + // NOTE: Do NOT call PushFreeSmallId here. The old PlayerConnection's + // write thread may still be alive (it dies in PlayerList::tick when + // m_smallIdsToClose is processed). If we recycle the smallId now, + // AcceptThread can reuse it for a new connection, and the old write + // thread's getPlayer() lookup will resolve to the NEW player, sending + // stale game packets to the new client's TCP socket — corrupting its + // login handshake (bad packet id crash). PushFreeSmallId and + // ClearSocketForSmallId are called from PlayerList::tick after the + // old Connection threads are dead. + // // Clear chunk visibility flags for this system so rejoin gets fresh chunk state. SystemFlagRemoveBySmallId((int)disconnectedSmallId); } @@ -289,12 +295,40 @@ int CPlatformNetworkManagerStub::GetLocalPlayerMask(int playerIndex) bool CPlatformNetworkManagerStub::AddLocalPlayerByUserIndex( int userIndex ) { - NotifyPlayerJoined(m_pIQNet->GetLocalPlayerByUserIndex(userIndex)); - return ( m_pIQNet->AddLocalPlayerByUserIndex(userIndex) == S_OK ); + if ( m_pIQNet->AddLocalPlayerByUserIndex(userIndex) != S_OK ) + return false; + // Player is now registered in IQNet — get a pointer and notify the network layer. + // Use the static array directly: GetLocalPlayerByUserIndex checks customData which + // isn't set until addNetworkPlayer runs inside NotifyPlayerJoined. + NotifyPlayerJoined(&IQNet::m_player[userIndex]); + return true; } bool CPlatformNetworkManagerStub::RemoveLocalPlayerByUserIndex( int userIndex ) { +#ifdef _WINDOWS64 + if (userIndex > 0 && userIndex < XUSER_MAX_COUNT && !m_pIQNet->IsHost()) + { + IQNetPlayer* qp = &IQNet::m_player[userIndex]; + + // Notify the network layer before clearing the slot + if (qp->GetCustomDataValue() != 0) + { + NotifyPlayerLeaving(qp); + } + + // Close the split-screen TCP connection and reset WinsockNetLayer state + WinsockNetLayer::CloseSplitScreenConnection(userIndex); + + // Clear the IQNet slot so it can be reused on rejoin + qp->m_smallId = 0; + qp->m_isRemote = false; + qp->m_isHostPlayer = false; + qp->m_resolvedXuid = INVALID_XUID; + qp->m_gamertag[0] = 0; + qp->SetCustomDataValue(0); + } +#endif return true; } |
