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.
This commit is contained in:
itsRevela
2026-03-31 17:27:24 -05:00
parent d5fafb74e8
commit aecef7f10d
2 changed files with 16 additions and 16 deletions

View File

@@ -273,22 +273,6 @@ bool PlayerList::placeNewPlayer(Connection *connection, shared_ptr<ServerPlayer>
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<LoginPacket>(L"", player->entityId, level->getLevelData()->getGenerator(),
level->getSeed(),
player->gameMode->getGameModeForPlayer()->getId(),
@@ -389,6 +373,16 @@ bool PlayerList::placeNewPlayer(Connection *connection, shared_ptr<ServerPlayer>
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

View File

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