2026-03-01 12:16:08 +08:00
# include "stdafx.h"
# include "PendingConnection.h"
# include "PlayerConnection.h"
# include "ServerConnection.h"
# include "ServerPlayer.h"
# include "ServerPlayerGameMode.h"
# include "ServerLevel.h"
# include "PlayerList.h"
# include "MinecraftServer.h"
# include "..\Minecraft.World\net.minecraft.network.h"
# include "..\Minecraft.World\pos.h"
# include "..\Minecraft.World\net.minecraft.world.level.dimension.h"
# include "..\Minecraft.World\net.minecraft.world.level.storage.h"
# include "..\Minecraft.World\net.minecraft.world.item.h"
# include "..\Minecraft.World\SharedConstants.h"
# include "Settings.h"
// #ifdef __PS3__
// #include "PS3\Network\NetworkPlayerSony.h"
// #endif
Random * PendingConnection : : random = new Random ( ) ;
2026-03-02 20:30:22 -03:00
# ifdef _WINDOWS64
bool g_bRejectDuplicateNames = true ;
# endif
2026-03-01 12:16:08 +08:00
PendingConnection : : PendingConnection ( MinecraftServer * server , Socket * socket , const wstring & id )
{
// 4J - added initialisers
done = false ;
2026-03-03 03:04:10 +08:00
_tick = 0 ;
name = L " " ;
acceptedLogin = nullptr ;
2026-03-01 12:16:08 +08:00
loginKey = L " " ;
2026-03-03 03:04:10 +08:00
this - > server = server ;
connection = new Connection ( socket , id , this ) ;
connection - > fakeLag = FAKE_LAG ;
2026-03-01 12:16:08 +08:00
}
PendingConnection : : ~ PendingConnection ( )
{
delete connection ;
}
void PendingConnection : : tick ( )
{
2026-03-08 19:08:36 -04:00
if ( acceptedLogin ! = nullptr )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
this - > handleAcceptedLogin ( acceptedLogin ) ;
acceptedLogin = nullptr ;
}
if ( _tick + + = = MAX_TICKS_BEFORE_LOGIN )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
disconnect ( DisconnectPacket : : eDisconnect_LoginTooLong ) ;
}
2026-03-01 12:16:08 +08:00
else
{
2026-03-03 03:04:10 +08:00
connection - > tick ( ) ;
}
2026-03-01 12:16:08 +08:00
}
void PendingConnection : : disconnect ( DisconnectPacket : : eDisconnectReason reason )
{
2026-03-03 03:04:10 +08:00
// try { // 4J - removed try/catch
// logger.info("Disconnecting " + getName() + ": " + reason);
app . DebugPrintf ( " Pending connection disconnect: %d \n " , reason ) ;
2026-03-08 19:08:36 -04:00
connection - > send ( std : : make_shared < DisconnectPacket > ( reason ) ) ;
2026-03-03 03:04:10 +08:00
connection - > sendAndQuit ( ) ;
done = true ;
// } catch (Exception e) {
// e.printStackTrace();
// }
2026-03-01 12:16:08 +08:00
}
2026-03-02 17:37:16 +07:00
void PendingConnection : : handlePreLogin ( shared_ptr < PreLoginPacket > packet )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
if ( packet - > m_netcodeVersion ! = MINECRAFT_NET_VERSION )
2026-03-01 12:16:08 +08:00
{
app . DebugPrintf ( " Netcode version is %d not equal to %d \n " , packet - > m_netcodeVersion , MINECRAFT_NET_VERSION ) ;
2026-03-03 03:04:10 +08:00
if ( packet - > m_netcodeVersion > MINECRAFT_NET_VERSION )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
disconnect ( DisconnectPacket : : eDisconnect_OutdatedServer ) ;
}
2026-03-01 12:16:08 +08:00
else
{
2026-03-03 03:04:10 +08:00
disconnect ( DisconnectPacket : : eDisconnect_OutdatedClient ) ;
}
return ;
}
// printf("Server: handlePreLogin\n");
2026-03-01 12:16:08 +08:00
name = packet - > loginKey ; // 4J Stu - Change from the login packet as we know better on client end during the pre-login packet
sendPreLoginResponse ( ) ;
}
void PendingConnection : : sendPreLoginResponse ( )
{
// 4J Stu - Calculate the players with UGC privileges set
PlayerUID * ugcXuids = new PlayerUID [ MINECRAFT_NET_MAX_PLAYERS ] ;
DWORD ugcXuidCount = 0 ;
DWORD hostIndex = 0 ;
BYTE ugcFriendsOnlyBits = 0 ;
char szUniqueMapName [ 14 ] ;
StorageManager . GetSaveUniqueFilename ( szUniqueMapName ) ;
PlayerList * playerList = MinecraftServer : : getInstance ( ) - > getPlayers ( ) ;
2026-03-06 02:11:18 +07:00
for ( auto & player : playerList - > players )
2026-03-01 12:16:08 +08:00
{
// If the offline Xuid is invalid but the online one is not then that's guest which we should ignore
// If the online Xuid is invalid but the offline one is not then we are definitely an offline game so dont care about UGC
2026-03-03 03:04:10 +08:00
2026-03-01 12:16:08 +08:00
// PADDY - this is failing when a local player with chat restrictions joins an online game
2026-03-06 02:11:18 +07:00
if ( player ! = nullptr & & player - > connection - > m_offlineXUID ! = INVALID_XUID & & player - > connection - > m_onlineXUID ! = INVALID_XUID )
2026-03-01 12:16:08 +08:00
{
if ( player - > connection - > m_friendsOnlyUGC )
{
ugcFriendsOnlyBits | = ( 1 < < ugcXuidCount ) ;
}
// Need to use the online XUID otherwise friend checks will fail on the client
ugcXuids [ ugcXuidCount ] = player - > connection - > m_onlineXUID ;
2026-03-08 19:08:36 -04:00
if ( player - > connection - > getNetworkPlayer ( ) ! = nullptr & & player - > connection - > getNetworkPlayer ( ) - > IsHost ( ) ) hostIndex = ugcXuidCount ;
2026-03-01 12:16:08 +08:00
+ + ugcXuidCount ;
}
}
#if 0
2026-03-03 03:04:10 +08:00
if ( false ) // server->onlineMode) // 4J - removed
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
loginKey = L " TOIMPLEMENT " ; // 4J - todo Long.toHexString(random.nextLong());
connection - > send ( shared_ptr < PreLoginPacket > ( new PreLoginPacket ( loginKey , ugcXuids , ugcXuidCount , ugcFriendsOnlyBits , server - > m_ugcPlayersVersion , szUniqueMapName , app . GetGameHostOption ( eGameHostOption_All ) , hostIndex ) ) ) ;
}
2026-03-01 12:16:08 +08:00
else
# endif
{
2026-03-08 19:08:36 -04:00
DWORD cappedCount = ( ugcXuidCount > 255u ) ? 255u : ugcXuidCount ;
2026-03-06 19:23:32 -06:00
BYTE cappedHostIndex = ( hostIndex > = 255u ) ? 254 : static_cast < BYTE > ( hostIndex ) ;
2026-03-08 19:08:36 -04:00
connection - > send ( std : : make_shared < PreLoginPacket > ( L " - " , ugcXuids , cappedCount , ugcFriendsOnlyBits , server - > m_ugcPlayersVersion , szUniqueMapName , app . GetGameHostOption ( eGameHostOption_All ) , cappedHostIndex , server - > m_texturePackId ) ) ;
2026-03-03 03:04:10 +08:00
}
2026-03-01 12:16:08 +08:00
}
2026-03-02 17:37:16 +07:00
void PendingConnection : : handleLogin ( shared_ptr < LoginPacket > packet )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
// printf("Server: handleLogin\n");
//name = packet->userName;
if ( packet - > clientVersion ! = SharedConstants : : NETWORK_PROTOCOL_VERSION )
2026-03-01 12:16:08 +08:00
{
app . DebugPrintf ( " Client version is %d not equal to %d \n " , packet - > clientVersion , SharedConstants : : NETWORK_PROTOCOL_VERSION ) ;
2026-03-03 03:04:10 +08:00
if ( packet - > clientVersion > SharedConstants : : NETWORK_PROTOCOL_VERSION )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
disconnect ( DisconnectPacket : : eDisconnect_OutdatedServer ) ;
}
2026-03-01 12:16:08 +08:00
else
{
2026-03-03 03:04:10 +08:00
disconnect ( DisconnectPacket : : eDisconnect_OutdatedClient ) ;
}
return ;
}
2026-03-01 12:16:08 +08:00
2026-03-03 03:04:10 +08:00
//if (true)// 4J removed !server->onlineMode)
2026-03-01 12:16:08 +08:00
bool sentDisconnect = false ;
2026-03-06 15:01:36 +09:00
// Use the same Xuid choice as handleAcceptedLogin (offline first, online fallback).
//
PlayerUID loginXuid = packet - > m_offlineXuid ;
if ( loginXuid = = INVALID_XUID ) loginXuid = packet - > m_onlineXuid ;
bool duplicateXuid = false ;
if ( loginXuid ! = INVALID_XUID & & server - > getPlayers ( ) - > getPlayer ( loginXuid ) ! = nullptr )
{
duplicateXuid = true ;
}
else if ( packet - > m_onlineXuid ! = INVALID_XUID & &
packet - > m_onlineXuid ! = loginXuid & &
server - > getPlayers ( ) - > getPlayer ( packet - > m_onlineXuid ) ! = nullptr )
{
duplicateXuid = true ;
}
2026-03-01 12:16:08 +08:00
if ( sentDisconnect )
{
// Do nothing
}
else if ( server - > getPlayers ( ) - > isXuidBanned ( packet - > m_onlineXuid ) )
{
disconnect ( DisconnectPacket : : eDisconnect_Banned ) ;
}
2026-03-06 15:01:36 +09:00
else if ( duplicateXuid )
{
2026-03-09 05:10:00 +01:00
// Reject the incoming connection — a player with this UID is already
// on the server. Allowing duplicates causes invisible players and
// other undefined behaviour.
app . DebugPrintf ( " LOGIN: Rejecting duplicate xuid for name: %ls \n " , name . c_str ( ) ) ;
disconnect ( DisconnectPacket : : eDisconnect_Banned ) ;
2026-03-06 15:01:36 +09:00
}
2026-03-02 20:30:22 -03:00
# ifdef _WINDOWS64
else if ( g_bRejectDuplicateNames )
{
bool nameTaken = false ;
vector < shared_ptr < ServerPlayer > > & pl = server - > getPlayers ( ) - > players ;
2026-03-06 02:11:18 +07:00
for ( const auto & i : pl )
2026-03-02 20:30:22 -03:00
{
2026-03-08 19:08:36 -04:00
if ( i ! = nullptr & & i - > name = = name )
2026-03-02 20:30:22 -03:00
{
nameTaken = true ;
break ;
}
}
if ( nameTaken )
{
app . DebugPrintf ( " Rejecting duplicate name: %ls \n " , name . c_str ( ) ) ;
disconnect ( DisconnectPacket : : eDisconnect_Banned ) ;
}
else
{
handleAcceptedLogin ( packet ) ;
}
}
# endif
2026-03-01 12:16:08 +08:00
else
{
2026-03-03 03:04:10 +08:00
handleAcceptedLogin ( packet ) ;
}
2026-03-01 12:16:08 +08:00
//else
{
//4J - removed
2026-03-06 02:11:18 +07:00
#if 0
2026-03-03 03:04:10 +08:00
new Thread ( ) {
public void run ( ) {
try {
String key = loginKey ;
URL url = new URL ( " http://www.minecraft.net/game/checkserver.jsp?user= " + URLEncoder . encode ( packet . userName , " UTF-8 " ) + " &serverId= " + URLEncoder . encode ( key , " UTF-8 " ) ) ;
BufferedReader br = new BufferedReader ( new InputStreamReader ( url . openStream ( ) ) ) ;
String msg = br . readLine ( ) ;
br . close ( ) ;
if ( msg . equals ( " YES " ) ) {
acceptedLogin = packet ;
} else {
disconnect ( " Failed to verify username! " ) ;
}
} catch ( Exception e ) {
disconnect ( " Failed to verify username! [internal error " + e + " ] " ) ;
e . printStackTrace ( ) ;
}
}
} . start ( ) ;
2026-03-01 12:16:08 +08:00
# endif
2026-03-03 03:04:10 +08:00
}
2026-03-01 12:16:08 +08:00
}
2026-03-02 17:37:16 +07:00
void PendingConnection : : handleAcceptedLogin ( shared_ptr < LoginPacket > packet )
2026-03-01 12:16:08 +08:00
{
if ( packet - > m_ugcPlayersVersion ! = server - > m_ugcPlayersVersion )
{
// Send the pre-login packet again with the new list of players
sendPreLoginResponse ( ) ;
return ;
}
// Guests use the online xuid, everyone else uses the offline one
PlayerUID playerXuid = packet - > m_offlineXuid ;
if ( playerXuid = = INVALID_XUID ) playerXuid = packet - > m_onlineXuid ;
2026-03-03 03:04:10 +08:00
shared_ptr < ServerPlayer > playerEntity = server - > getPlayers ( ) - > getPlayerForLogin ( this , name , playerXuid , packet - > m_onlineXuid ) ;
2026-03-08 19:08:36 -04:00
if ( playerEntity ! = nullptr )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
server - > getPlayers ( ) - > placeNewPlayer ( connection , playerEntity , packet ) ;
2026-03-08 19:08:36 -04:00
connection = nullptr ; // We've moved responsibility for this over to the new PlayerConnection, nullptr so we don't delete our reference to it here in our dtor
2026-03-03 03:04:10 +08:00
}
done = true ;
2026-03-01 12:16:08 +08:00
}
void PendingConnection : : onDisconnect ( DisconnectPacket : : eDisconnectReason reason , void * reasonObjects )
{
2026-03-03 03:04:10 +08:00
// logger.info(getName() + " lost connection");
done = true ;
2026-03-01 12:16:08 +08:00
}
2026-03-02 17:37:16 +07:00
void PendingConnection : : handleGetInfo ( shared_ptr < GetInfoPacket > packet )
2026-03-01 12:16:08 +08:00
{
//try {
2026-03-06 02:11:18 +07:00
//String message = server->motd + "<22> " + server->players->getPlayerCount() + "<22> " + server->players->getMaxPlayers();
2026-03-01 12:16:08 +08:00
//connection->send(new DisconnectPacket(message));
2026-03-08 19:08:36 -04:00
connection - > send ( std : : make_shared < DisconnectPacket > ( DisconnectPacket : : eDisconnect_ServerFull ) ) ;
2026-03-01 12:16:08 +08:00
connection - > sendAndQuit ( ) ;
server - > connection - > removeSpamProtection ( connection - > getSocket ( ) ) ;
done = true ;
//} catch (Exception e) {
// e.printStackTrace();
//}
}
2026-03-02 17:37:16 +07:00
void PendingConnection : : handleKeepAlive ( shared_ptr < KeepAlivePacket > packet )
2026-03-01 12:16:08 +08:00
{
// Ignore
}
2026-03-02 17:37:16 +07:00
void PendingConnection : : onUnhandledPacket ( shared_ptr < Packet > packet )
2026-03-01 12:16:08 +08:00
{
disconnect ( DisconnectPacket : : eDisconnect_UnexpectedPacket ) ;
}
2026-03-02 17:37:16 +07:00
void PendingConnection : : send ( shared_ptr < Packet > packet )
2026-03-01 12:16:08 +08:00
{
connection - > send ( packet ) ;
}
wstring PendingConnection : : getName ( )
{
return L " Unimplemented " ;
2026-03-03 03:04:10 +08:00
// if (name != null) return name + " [" + connection.getRemoteAddress().toString() + "]";
// return connection.getRemoteAddress().toString();
2026-03-01 12:16:08 +08:00
}
bool PendingConnection : : isServerPacketListener ( )
{
return true ;
2026-03-03 03:04:10 +08:00
}
bool PendingConnection : : isDisconnected ( )
{
return done ;
2026-03-01 12:16:08 +08:00
}