aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.Client/Common/Network
diff options
context:
space:
mode:
Diffstat (limited to 'Minecraft.Client/Common/Network')
-rw-r--r--Minecraft.Client/Common/Network/GameNetworkManager.cpp44
-rw-r--r--Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp46
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;
}