From aecef7f10dcf5ca50ccf6dec732f9f8e55a9a7c0 Mon Sep 17 00:00:00 2001 From: itsRevela Date: Tue, 31 Mar 2026 17:27:24 -0500 Subject: [PATCH] fix: move security gate close after login sequence to prevent high-latency crashes The security gate was closed before LoginPacket was sent in placeNewPlayer, causing all login setup packets to be buffered behind the cipher handshake. Under high-latency connections, the flushed data arrived before the player object was initialized, causing a null pointer crash. The gate now closes after the login sequence and MC|CKey are sent. --- Minecraft.Client/PlayerList.cpp | 26 ++++++++++---------------- README.md | 6 ++++++ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Minecraft.Client/PlayerList.cpp b/Minecraft.Client/PlayerList.cpp index 3d7e8f9c..153f8f45 100644 --- a/Minecraft.Client/PlayerList.cpp +++ b/Minecraft.Client/PlayerList.cpp @@ -273,22 +273,6 @@ bool PlayerList::placeNewPlayer(Connection *connection, shared_ptr app.DebugPrintf("RECONNECT: placeNewPlayer smallId=%d entityId=%d dim=%d\n", newSmallId, player->entityId, level->dimension->id); -#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD) - // Close the security gate before sending any game data. All packets will be - // buffered until the cipher handshake completes, preventing unsecured clients - // from receiving XUIDs or game state during the grace period. - if (g_Win64DedicatedServer && - ServerRuntime::Security::GetSettings().enableStreamCipher && - ServerRuntime::Security::GetSettings().requireSecureClient) - { - INetworkPlayer *gateNp = connection->getSocket() ? connection->getSocket()->getPlayer() : nullptr; - if (gateNp != nullptr && !gateNp->IsLocal()) - { - playerConnection->m_securityGateOpen = false; - } - } -#endif - playerConnection->send(std::make_shared(L"", player->entityId, level->getLevelData()->getGenerator(), level->getSeed(), player->gameMode->getGameModeForPlayer()->getId(), @@ -389,6 +373,16 @@ bool PlayerList::placeNewPlayer(Connection *connection, shared_ptr ServerRuntime::Security::GetHandshakeEnforcer().OnCipherKeySent(smallId, s_playerListTickCount); } } + + // Close the security gate AFTER sending the essential login sequence + // and MC|CKey. The login setup packets (LoginPacket, spawn position, + // abilities, chunks, teleport) must arrive in plaintext before the + // cipher handshake completes. Only subsequent tick data is buffered + // until the handshake finishes and openSecurityGate() flushes. + if (ServerRuntime::Security::GetSettings().requireSecureClient) + { + playerConnection->m_securityGateOpen = false; + } } } #endif diff --git a/README.md b/README.md index d3319b21..63c83176 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,12 @@ This project is based on source code of Minecraft Legacy Console Edition v1.6.05 ## Latest: +### Security Gate Hotfix (Dedicated Server) + +- Fixed a critical bug where the security gate (packet buffer) was closed before the LoginPacket was sent during `placeNewPlayer`. Under high-latency connections (e.g. players connecting through tunnels or from distant regions), the LoginPacket and all login setup packets were buffered behind the cipher handshake. When the handshake completed and the gate flushed, game data arrived before the player object was initialized, causing a null pointer crash on the client +- The security gate now closes after the login sequence and MC|CKey are sent, so essential setup packets arrive in plaintext before the cipher handshake completes +- **Server owners must update their dedicated server binary to this version.** Players connecting to an updated server must also use the updated client (LCRE builds that include the cipher handshake support) + ### Uncapped FPS (VSync Off) - FPS is no longer locked to the monitor's refresh rate when VSync is disabled. The precompiled 4J render library hardcodes `SyncInterval=1` in its Present call, which forced VBlank synchronization regardless of the VSync setting. The main loop now bypasses the library's Present and calls the DXGI swap chain directly with `SyncInterval=0` and `DXGI_PRESENT_ALLOW_TEARING` when VSync is off