diff options
Diffstat (limited to 'Minecraft.Client')
| -rw-r--r-- | Minecraft.Client/Common/Console_Utils.cpp | 36 | ||||
| -rw-r--r-- | Minecraft.Client/Common/Consoles_App.cpp | 117 | ||||
| -rw-r--r-- | Minecraft.Client/Common/Network/GameNetworkManager.cpp | 53 | ||||
| -rw-r--r-- | Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp | 50 | ||||
| -rw-r--r-- | Minecraft.Client/MinecraftServer.cpp | 10 | ||||
| -rw-r--r-- | Minecraft.Client/MinecraftServer.h | 3 | ||||
| -rw-r--r-- | Minecraft.Client/PendingConnection.cpp | 72 | ||||
| -rw-r--r-- | Minecraft.Client/PlayerConnection.cpp | 104 | ||||
| -rw-r--r-- | Minecraft.Client/PlayerConnection.h | 5 | ||||
| -rw-r--r-- | Minecraft.Client/PlayerList.cpp | 12 | ||||
| -rw-r--r-- | Minecraft.Client/ServerPlayerGameMode.cpp | 32 | ||||
| -rw-r--r-- | Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp | 103 | ||||
| -rw-r--r-- | Minecraft.Client/Windows64/Network/WinsockNetLayer.h | 1 |
13 files changed, 463 insertions, 135 deletions
diff --git a/Minecraft.Client/Common/Console_Utils.cpp b/Minecraft.Client/Common/Console_Utils.cpp index cb0f1b58..9a64dbea 100644 --- a/Minecraft.Client/Common/Console_Utils.cpp +++ b/Minecraft.Client/Common/Console_Utils.cpp @@ -1,21 +1,32 @@ #include "stdafx.h" +#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD) +#include "..\..\Minecraft.Server\ServerLogManager.h" +#endif //-------------------------------------------------------------------------------------- // Name: DebugSpewV() // Desc: Internal helper function //-------------------------------------------------------------------------------------- #ifndef _CONTENT_PACKAGE -static VOID DebugSpewV( const CHAR* strFormat, const va_list pArgList ) +static VOID DebugSpewV( const CHAR* strFormat, va_list pArgList ) { #if defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ - assert(0); + assert(0); #else - CHAR str[2048]; - // Use the secure CRT to avoid buffer overruns. Specify a count of - // _TRUNCATE so that too long strings will be silently truncated - // rather than triggering an error. - _vsnprintf_s( str, _TRUNCATE, strFormat, pArgList ); - OutputDebugStringA( str ); +#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD) + // Dedicated server routes legacy debug spew through ServerLogger to preserve CLI prompt handling. + if (ServerRuntime::ServerLogManager::ShouldForwardClientDebugLogs()) + { + ServerRuntime::ServerLogManager::ForwardClientDebugSpewLogV(strFormat, pArgList); + return; + } +#endif + CHAR str[2048]; + // Use the secure CRT to avoid buffer overruns. Specify a count of + // _TRUNCATE so that too long strings will be silently truncated + // rather than triggering an error. + _vsnprintf_s( str, _TRUNCATE, strFormat, pArgList ); + OutputDebugStringA( str ); #endif } #endif @@ -31,10 +42,9 @@ VOID CDECL DebugPrintf( const CHAR* strFormat, ... ) #endif { #ifndef _CONTENT_PACKAGE - va_list pArgList; - va_start( pArgList, strFormat ); - DebugSpewV( strFormat, pArgList ); - va_end( pArgList ); + va_list pArgList; + va_start( pArgList, strFormat ); + DebugSpewV( strFormat, pArgList ); + va_end( pArgList ); #endif } - diff --git a/Minecraft.Client/Common/Consoles_App.cpp b/Minecraft.Client/Common/Consoles_App.cpp index c3a623d5..0a2fd159 100644 --- a/Minecraft.Client/Common/Consoles_App.cpp +++ b/Minecraft.Client/Common/Consoles_App.cpp @@ -38,6 +38,9 @@ #include "GameRules\ConsoleSchematicFile.h" #include "..\User.h" #include "..\..\Minecraft.World\LevelData.h" +#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD) +#include "..\..\Minecraft.Server\ServerLogManager.h" +#endif #include "..\..\Minecraft.World\net.minecraft.world.entity.player.h" #include "..\EntityRenderDispatcher.h" #include "..\..\Minecraft.World\compression.h" @@ -240,12 +243,21 @@ void CMinecraftApp::DebugPrintf(const char *szFormat, ...) { #ifndef _FINAL_BUILD - char buf[1024]; - va_list ap; - va_start(ap, szFormat); - vsnprintf(buf, sizeof(buf), szFormat, ap); - va_end(ap); - OutputDebugStringA(buf); + va_list ap; + va_start(ap, szFormat); +#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD) + // Dedicated server routes client debug spew through ServerLogger so CLI output stays prompt-safe. + if (ServerRuntime::ServerLogManager::ShouldForwardClientDebugLogs()) + { + ServerRuntime::ServerLogManager::ForwardClientAppDebugLogV(szFormat, ap); + va_end(ap); + return; + } +#endif + char buf[1024]; + vsnprintf(buf, sizeof(buf), szFormat, ap); + va_end(ap); + OutputDebugStringA(buf); #endif } @@ -253,53 +265,62 @@ void CMinecraftApp::DebugPrintf(const char *szFormat, ...) void CMinecraftApp::DebugPrintf(int user, const char *szFormat, ...) { #ifndef _FINAL_BUILD - if(user == USER_NONE) - return; - char buf[1024]; - va_list ap; - va_start(ap, szFormat); - vsnprintf(buf, sizeof(buf), szFormat, ap); - va_end(ap); + if(user == USER_NONE) + return; + va_list ap; + va_start(ap, szFormat); +#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD) + // Dedicated server routes client debug spew through ServerLogger so CLI output stays prompt-safe. + if (ServerRuntime::ServerLogManager::ShouldForwardClientDebugLogs()) + { + ServerRuntime::ServerLogManager::ForwardClientUserDebugLogV(user, szFormat, ap); + va_end(ap); + return; + } +#endif + char buf[1024]; + vsnprintf(buf, sizeof(buf), szFormat, ap); + va_end(ap); #ifdef __PS3__ - unsigned int writelen; - sys_tty_write(SYS_TTYP_USER1 + ( user - 1 ), buf, strlen(buf), &writelen ); + unsigned int writelen; + sys_tty_write(SYS_TTYP_USER1 + ( user - 1 ), buf, strlen(buf), &writelen ); #elif defined __PSVITA__ - switch(user) - { - case 0: - { - SceUID tty2 = sceIoOpen("tty2:", SCE_O_WRONLY, 0); - if(tty2>=0) - { - std::string string1(buf); - sceIoWrite(tty2, string1.c_str(), string1.length()); - sceIoClose(tty2); - } - } - break; - case 1: - { - SceUID tty3 = sceIoOpen("tty3:", SCE_O_WRONLY, 0); - if(tty3>=0) - { - std::string string1(buf); - sceIoWrite(tty3, string1.c_str(), string1.length()); - sceIoClose(tty3); - } - } - break; - default: - OutputDebugStringA(buf); - break; - } + switch(user) + { + case 0: + { + SceUID tty2 = sceIoOpen("tty2:", SCE_O_WRONLY, 0); + if(tty2>=0) + { + std::string string1(buf); + sceIoWrite(tty2, string1.c_str(), string1.length()); + sceIoClose(tty2); + } + } + break; + case 1: + { + SceUID tty3 = sceIoOpen("tty3:", SCE_O_WRONLY, 0); + if(tty3>=0) + { + std::string string1(buf); + sceIoWrite(tty3, string1.c_str(), string1.length()); + sceIoClose(tty3); + } + } + break; + default: + OutputDebugStringA(buf); + break; + } #else - OutputDebugStringA(buf); + OutputDebugStringA(buf); #endif #ifndef _XBOX - if(user == USER_UI) - { - ui.logDebugString(buf); - } + if(user == USER_UI) + { + ui.logDebugString(buf); + } #endif #endif } diff --git a/Minecraft.Client/Common/Network/GameNetworkManager.cpp b/Minecraft.Client/Common/Network/GameNetworkManager.cpp index a502dbfb..50aeae68 100644 --- a/Minecraft.Client/Common/Network/GameNetworkManager.cpp +++ b/Minecraft.Client/Common/Network/GameNetworkManager.cpp @@ -200,10 +200,12 @@ bool CGameNetworkManager::StartNetworkGame(Minecraft *minecraft, LPVOID lpParame #endif int64_t seed = 0; + bool dedicatedNoLocalHostPlayer = false; if (lpParameter != nullptr) { NetworkGameInitData *param = static_cast<NetworkGameInitData *>(lpParameter); seed = param->seed; + dedicatedNoLocalHostPlayer = param->dedicatedNoLocalHostPlayer; app.setLevelGenerationOptions(param->levelGen); if(param->levelGen != nullptr) @@ -359,9 +361,19 @@ bool CGameNetworkManager::StartNetworkGame(Minecraft *minecraft, LPVOID lpParame // PRIMARY PLAYER vector<ClientConnection *> createdConnections; - ClientConnection *connection; + ClientConnection *connection = nullptr; - if( g_NetworkManager.IsHost() ) + if( g_NetworkManager.IsHost() && dedicatedNoLocalHostPlayer ) + { + app.DebugPrintf("Dedicated server mode: skipping local host client connection\n"); + + // Keep telemetry behavior consistent with the host path. + INT multiplayerInstanceId = TelemetryManager->GenerateMultiplayerInstanceId(); + TelemetryManager->SetMultiplayerInstanceId(multiplayerInstanceId); + + app.SetGameMode( eMode_Multiplayer ); + } + else if( g_NetworkManager.IsHost() ) { connection = new ClientConnection(minecraft, nullptr); } @@ -390,16 +402,18 @@ bool CGameNetworkManager::StartNetworkGame(Minecraft *minecraft, LPVOID lpParame connection = new ClientConnection(minecraft, socket); } - if( !connection->createdOk ) + if (connection != nullptr) { - assert(false); - delete connection; - connection = nullptr; - MinecraftServer::HaltServer(); - return false; - } + if( !connection->createdOk ) + { + assert(false); + delete connection; + connection = nullptr; + MinecraftServer::HaltServer(); + return false; + } - connection->send(std::make_shared<PreLoginPacket>(minecraft->user->name)); + connection->send(std::make_shared<PreLoginPacket>(minecraft->user->name)); // Tick connection until we're ready to go. The stages involved in this are: // (1) Creating the ClientConnection sends a prelogin packet to the server @@ -434,9 +448,9 @@ bool CGameNetworkManager::StartNetworkGame(Minecraft *minecraft, LPVOID lpParame connection->close(); } - if( connection->isStarted() && !connection->isClosed() ) - { - createdConnections.push_back( connection ); + if( connection->isStarted() && !connection->isClosed() ) + { + createdConnections.push_back( connection ); int primaryPad = ProfileManager.GetPrimaryPad(); app.SetRichPresenceContext(primaryPad,CONTEXT_GAME_STATE_BLANK); @@ -533,13 +547,14 @@ bool CGameNetworkManager::StartNetworkGame(Minecraft *minecraft, LPVOID lpParame } } - app.SetGameMode( eMode_Multiplayer ); - } - else if ( connection->isClosed() || !IsInSession()) - { + app.SetGameMode( eMode_Multiplayer ); + } + else if ( connection->isClosed() || !IsInSession()) + { // assert(false); - MinecraftServer::HaltServer(); - return false; + MinecraftServer::HaltServer(); + return false; + } } diff --git a/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp index 7340a7e0..1e625098 100644 --- a/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp +++ b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp @@ -240,7 +240,13 @@ void CPlatformNetworkManagerStub::DoWork() qnetPlayer->m_resolvedXuid = INVALID_XUID; qnetPlayer->m_gamertag[0] = 0; qnetPlayer->SetCustomDataValue(0); - while (IQNet::s_playerCount > 1 && IQNet::m_player[IQNet::s_playerCount - 1].GetCustomDataValue() == 0) + // Recalculate s_playerCount as the highest active slot + 1. + // A blind decrement would hide players at higher-indexed slots when a + // lower-indexed player disconnects first: GetPlayerBySmallId scans + // [0, s_playerCount) so any slot at or above the decremented count + // becomes invisible, causing its disconnect to be missed (ghost player). + while (IQNet::s_playerCount > 1 && + IQNet::m_player[IQNet::s_playerCount - 1].GetCustomDataValue() == 0) IQNet::s_playerCount--; } // NOTE: Do NOT call PushFreeSmallId here. The old PlayerConnection's @@ -257,6 +263,25 @@ void CPlatformNetworkManagerStub::DoWork() SystemFlagRemoveBySmallId(disconnectedSmallId); } } + + // Client-side host disconnect detection: + // if TCP is gone, propagate through normal network-disconnect flow so UI returns to menus. + // The processing from the Xbox version will be reused. + if (_iQNetStubState == QNET_STATE_GAME_PLAY && !m_pIQNet->IsHost() && !m_bLeavingGame) + { + if (!WinsockNetLayer::IsConnected()) + { + if (!m_bLeaveGameOnTick) + { + m_bLeaveGameOnTick = true; + g_NetworkManager.HandleDisconnect(false); + } + } + else + { + m_bLeaveGameOnTick = false; + } + } #endif } @@ -356,6 +381,7 @@ bool CPlatformNetworkManagerStub::LeaveGame(bool bMigrateHost) if( m_bLeavingGame ) return true; m_bLeavingGame = true; + m_bLeaveGameOnTick = false; #ifdef _WINDOWS64 WinsockNetLayer::StopAdvertising(); @@ -404,6 +430,7 @@ void CPlatformNetworkManagerStub::HostGame(int localUsersMask, bool bOnlineGame, localUsersMask |= GetLocalPlayerMask( g_NetworkManager.GetPrimaryPad() ); m_bLeavingGame = false; + m_bLeaveGameOnTick = false; m_pIQNet->HostGame(); @@ -433,9 +460,23 @@ void CPlatformNetworkManagerStub::HostGame(int localUsersMask, bool bOnlineGame, if (WinsockNetLayer::IsActive()) { - const wchar_t* hostName = IQNet::m_player[0].m_gamertag; - unsigned int settings = app.GetGameHostOption(eGameHostOption_All); - WinsockNetLayer::StartAdvertising(port, hostName, settings, 0, 0, MINECRAFT_NET_VERSION); + // For Dedicated Server, refer to `lan-advertise` in `server.properties` + bool enableLanAdvertising = true; + if (g_Win64DedicatedServer) + { + enableLanAdvertising = g_Win64DedicatedServerLanAdvertise; + } + + if (enableLanAdvertising) + { + const wchar_t* hostName = IQNet::m_player[0].m_gamertag; + unsigned int settings = app.GetGameHostOption(eGameHostOption_All); + WinsockNetLayer::StartAdvertising(port, hostName, settings, 0, 0, MINECRAFT_NET_VERSION); + } + else + { + WinsockNetLayer::StopAdvertising(); + } } #endif //#endif @@ -463,6 +504,7 @@ int CPlatformNetworkManagerStub::JoinGame(FriendSessionInfo* searchResult, int l return CGameNetworkManager::JOINGAME_FAIL_GENERAL; m_bLeavingGame = false; + m_bLeaveGameOnTick = false; IQNet::s_isHosting = false; m_pIQNet->ClientJoinGame(); diff --git a/Minecraft.Client/MinecraftServer.cpp b/Minecraft.Client/MinecraftServer.cpp index 2cf6930a..a545eff8 100644 --- a/Minecraft.Client/MinecraftServer.cpp +++ b/Minecraft.Client/MinecraftServer.cpp @@ -569,6 +569,7 @@ MinecraftServer::MinecraftServer() playerIdleTimeout = 0; m_postUpdateThread = nullptr; forceGameType = false; + m_spawnProtectionRadius = 0; commandDispatcher = new ServerCommandDispatcher(); InitializeCriticalSection(&m_consoleInputCS); @@ -615,6 +616,10 @@ bool MinecraftServer::initServer(int64_t seed, NetworkGameInitData *initData, DW logger.info("Loading properties"); #endif settings = new Settings(new File(L"server.properties")); + // Dedicated-only: spawn-protection radius in blocks; 0 disables protection. + m_spawnProtectionRadius = GetDedicatedServerInt(settings, L"spawn-protection", 0); + if (m_spawnProtectionRadius < 0) m_spawnProtectionRadius = 0; + if (m_spawnProtectionRadius > 256) m_spawnProtectionRadius = 256; app.SetGameHostOption(eGameHostOption_Difficulty, GetDedicatedServerInt(settings, L"difficulty", app.GetGameHostOption(eGameHostOption_Difficulty))); app.SetGameHostOption(eGameHostOption_GameType, GetDedicatedServerInt(settings, L"gamemode", app.GetGameHostOption(eGameHostOption_GameType))); @@ -631,6 +636,7 @@ bool MinecraftServer::initServer(int64_t seed, NetworkGameInitData *initData, DW app.DebugPrintf("ServerSettings: pvp is %s\n",(app.GetGameHostOption(eGameHostOption_PvP)>0)?"on":"off"); app.DebugPrintf("ServerSettings: fire spreads is %s\n",(app.GetGameHostOption(eGameHostOption_FireSpreads)>0)?"on":"off"); app.DebugPrintf("ServerSettings: tnt explodes is %s\n",(app.GetGameHostOption(eGameHostOption_TNT)>0)?"on":"off"); + app.DebugPrintf("ServerSettings: spawn protection radius is %d\n", m_spawnProtectionRadius); app.DebugPrintf("\n"); // TODO 4J Stu - Init a load of settings based on data passed as params @@ -1661,7 +1667,9 @@ Level *MinecraftServer::getCommandSenderWorld() int MinecraftServer::getSpawnProtectionRadius() { - return 16; + // Client-host mode must never apply dedicated-server spawn protection settings. + if (!ShouldUseDedicatedServerProperties()) return 0; + return m_spawnProtectionRadius; } bool MinecraftServer::isUnderSpawnProtection(Level *level, int x, int y, int z, shared_ptr<Player> player) diff --git a/Minecraft.Client/MinecraftServer.h b/Minecraft.Client/MinecraftServer.h index a33888bc..1ed5db9d 100644 --- a/Minecraft.Client/MinecraftServer.h +++ b/Minecraft.Client/MinecraftServer.h @@ -44,6 +44,7 @@ typedef struct _NetworkGameInitData LevelGenerationOptions *levelGen; DWORD texturePackId; bool findSeed; + bool dedicatedNoLocalHostPlayer; unsigned int xzSize; unsigned char hellScale; ESavePlatform savePlatform; @@ -57,6 +58,7 @@ typedef struct _NetworkGameInitData levelGen = nullptr; texturePackId = 0; findSeed = false; + dedicatedNoLocalHostPlayer = false; xzSize = LEVEL_LEGACY_WIDTH; hellScale = HELL_LEVEL_LEGACY_SCALE; savePlatform = SAVE_FILE_PLATFORM_LOCAL; @@ -119,6 +121,7 @@ public: int maxBuildHeight; int playerIdleTimeout; bool forceGameType; + int m_spawnProtectionRadius; private: // 4J Added diff --git a/Minecraft.Client/PendingConnection.cpp b/Minecraft.Client/PendingConnection.cpp index 6d5497f0..f24086c1 100644 --- a/Minecraft.Client/PendingConnection.cpp +++ b/Minecraft.Client/PendingConnection.cpp @@ -14,6 +14,11 @@ #include "..\Minecraft.World\net.minecraft.world.item.h" #include "..\Minecraft.World\SharedConstants.h" #include "Settings.h" +#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD) +#include "..\Minecraft.Server\ServerLogManager.h" +#include "..\Minecraft.Server\Access\Access.h" +#include "..\Minecraft.World\Socket.h" +#endif // #ifdef __PS3__ // #include "PS3\Network\NetworkPlayerSony.h" // #endif @@ -24,6 +29,24 @@ Random *PendingConnection::random = new Random(); bool g_bRejectDuplicateNames = true; #endif +#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD) +namespace +{ + static unsigned char GetPendingConnectionSmallId(Connection *connection) + { + if (connection != nullptr) + { + Socket *socket = connection->getSocket(); + if (socket != nullptr) + { + return socket->getSmallId(); + } + } + return 0; + } +} +#endif + PendingConnection::PendingConnection(MinecraftServer *server, Socket *socket, const wstring& id) { // 4J - added initialisers @@ -180,16 +203,55 @@ void PendingConnection::handleLogin(shared_ptr<LoginPacket> packet) duplicateXuid = true; } + bool bannedXuid = false; + if (loginXuid != INVALID_XUID) + { + bannedXuid = server->getPlayers()->isXuidBanned(loginXuid); + } + if (!bannedXuid && packet->m_onlineXuid != INVALID_XUID && packet->m_onlineXuid != loginXuid) + { + bannedXuid = server->getPlayers()->isXuidBanned(packet->m_onlineXuid); + } + + bool whitelistSatisfied = true; +#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD) + if (ServerRuntime::Access::IsWhitelistEnabled()) + { + whitelistSatisfied = false; + if (loginXuid != INVALID_XUID) + { + whitelistSatisfied = ServerRuntime::Access::IsPlayerWhitelisted(loginXuid); + } + if (!whitelistSatisfied && packet->m_onlineXuid != INVALID_XUID && packet->m_onlineXuid != loginXuid) + { + whitelistSatisfied = ServerRuntime::Access::IsPlayerWhitelisted(packet->m_onlineXuid); + } + } +#endif + if( sentDisconnect ) { // Do nothing } - else if( server->getPlayers()->isXuidBanned( packet->m_onlineXuid ) ) + else if (bannedXuid) + { +#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD) + ServerRuntime::ServerLogManager::OnRejectedPlayerLogin(GetPendingConnectionSmallId(connection), name, ServerRuntime::ServerLogManager::eLoginRejectReason_BannedXuid); +#endif + disconnect(DisconnectPacket::eDisconnect_Banned); + } + else if (!whitelistSatisfied) { +#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD) + ServerRuntime::ServerLogManager::OnRejectedPlayerLogin(GetPendingConnectionSmallId(connection), name, ServerRuntime::ServerLogManager::eLoginRejectReason_NotWhitelisted); +#endif disconnect(DisconnectPacket::eDisconnect_Banned); } else if (duplicateXuid) { +#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD) + ServerRuntime::ServerLogManager::OnRejectedPlayerLogin(GetPendingConnectionSmallId(connection), name, ServerRuntime::ServerLogManager::eLoginRejectReason_DuplicateXuid); +#endif // Reject the incoming connection — a player with this UID is already // on the server. Allowing duplicates causes invisible players and // other undefined behaviour. @@ -211,6 +273,9 @@ void PendingConnection::handleLogin(shared_ptr<LoginPacket> packet) } if (nameTaken) { +#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD) + ServerRuntime::ServerLogManager::OnRejectedPlayerLogin(GetPendingConnectionSmallId(connection), name, ServerRuntime::ServerLogManager::eLoginRejectReason_DuplicateName); +#endif app.DebugPrintf("Rejecting duplicate name: %ls\n", name.c_str()); disconnect(DisconnectPacket::eDisconnect_Banned); } @@ -268,6 +333,9 @@ void PendingConnection::handleAcceptedLogin(shared_ptr<LoginPacket> packet) shared_ptr<ServerPlayer> playerEntity = server->getPlayers()->getPlayerForLogin(this, name, playerXuid,packet->m_onlineXuid); if (playerEntity != nullptr) { +#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD) + ServerRuntime::ServerLogManager::OnAcceptedPlayerLogin(GetPendingConnectionSmallId(connection), name); +#endif server->getPlayers()->placeNewPlayer(connection, playerEntity, packet); 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 } @@ -325,4 +393,4 @@ bool PendingConnection::isServerPacketListener() bool PendingConnection::isDisconnected() { return done; -}
\ No newline at end of file +} diff --git a/Minecraft.Client/PlayerConnection.cpp b/Minecraft.Client/PlayerConnection.cpp index d9915cf6..6319b660 100644 --- a/Minecraft.Client/PlayerConnection.cpp +++ b/Minecraft.Client/PlayerConnection.cpp @@ -34,9 +34,26 @@ // 4J Added #include "..\Minecraft.World\net.minecraft.world.item.crafting.h" #include "Options.h" +#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD) +#include "..\Minecraft.Server\ServerLogManager.h" +#endif + +namespace +{ + // Anti-cheat thresholds. Keep server-side checks authoritative even in host mode. + // Base max squared displacement allowed per move packet before speed flags trigger. + const double kMoveBaseAllowanceSq = 100.0; + // Extra squared displacement allowance derived from current server-side velocity. + const double kMoveVelocityAllowanceScale = 100.0; + // Max squared distance for interact/attack when the target is visible (normal reach). + const double kInteractReachSq = 6.0 * 6.0; + // Stricter max squared distance used when LOS is blocked to reduce wall-hit abuse. + const double kInteractBlockedReachSq = 3.0 * 3.0; +} Random PlayerConnection::random; + PlayerConnection::PlayerConnection(MinecraftServer *server, Connection *connection, shared_ptr<ServerPlayer> player) { // 4J - added initialisers @@ -66,6 +83,13 @@ PlayerConnection::PlayerConnection(MinecraftServer *server, Connection *connecti m_offlineXUID = INVALID_XUID; m_onlineXUID = INVALID_XUID; m_bHasClientTickedOnce = false; + m_logSmallId = 0; + + // Cache the first valid transport smallId because disconnect teardown can clear it before the server logger runs. + if (this->connection != NULL && this->connection->getSocket() != NULL) + { + m_logSmallId = this->connection->getSocket()->getSmallId(); + } setShowOnMaps(app.GetGameHostOption(eGameHostOption_Gamertags)!=0?true:false); } @@ -76,6 +100,17 @@ PlayerConnection::~PlayerConnection() DeleteCriticalSection(&done_cs); } +unsigned char PlayerConnection::getLogSmallId() +{ + // Fall back to the live socket only while the cached value is still empty. + if (m_logSmallId == 0 && connection != NULL && connection->getSocket() != NULL) + { + m_logSmallId = connection->getSocket()->getSmallId(); + } + + return m_logSmallId; +} + void PlayerConnection::tick() { if( done ) return; @@ -118,6 +153,13 @@ void PlayerConnection::disconnect(DisconnectPacket::eDisconnectReason reason) return; } +#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD) + ServerRuntime::ServerLogManager::OnPlayerDisconnected( + getLogSmallId(), + (player != NULL) ? player->name : std::wstring(), + reason, + true); +#endif app.DebugPrintf("PlayerConnection disconect reason: %d\n", reason ); player->disconnect(); @@ -271,16 +313,19 @@ void PlayerConnection::handleMovePlayer(shared_ptr<MovePlayerPacket> packet) double dist = xDist * xDist + yDist * yDist + zDist * zDist; - // 4J-PB - removing this one for now - /*if (dist > 100.0f) + // Anti-cheat: reject movement packets that exceed server-authoritative bounds. + double velocitySq = player->xd * player->xd + player->yd * player->yd + player->zd * player->zd; + double maxAllowedSq = kMoveBaseAllowanceSq + (velocitySq * kMoveVelocityAllowanceScale); + if (player->isAllowedToFly() || player->gameMode->isCreative()) { - // logger.warning(player->name + " moved too quickly!"); - disconnect(DisconnectPacket::eDisconnect_MovedTooQuickly); - // System.out.println("Moved too quickly at " + xt + ", " + yt + ", " + zt); - // teleport(player->x, player->y, player->z, player->yRot, player->xRot); - return; + // Creative / flight-allowed players can move farther legitimately per tick. + maxAllowedSq *= 1.5; + } + if (dist > maxAllowedSq) + { + disconnect(DisconnectPacket::eDisconnect_MovedTooQuickly); + return; } - */ float r = 1 / 16.0f; bool oldOk = level->getCubes(player, player->bb->copy()->shrink(r, r, r))->empty(); @@ -308,8 +353,8 @@ void PlayerConnection::handleMovePlayer(shared_ptr<MovePlayerPacket> packet) xDist = xt - player->x; yDist = yt - player->y; - // 4J-PB - line below will always be true! - if (yDist > -0.5 || yDist < 0.5) + // Clamp tiny Y drift noise to reduce false positives. + if (yDist > -0.5 && yDist < 0.5) { yDist = 0; } @@ -430,7 +475,8 @@ void PlayerConnection::handlePlayerAction(shared_ptr<PlayerActionPacket> packet) if (packet->action == PlayerActionPacket::START_DESTROY_BLOCK) { - if (true) player->gameMode->startDestroyBlock(x, y, z, packet->face); // 4J - condition was !server->isUnderSpawnProtection(level, x, y, z, player) (from Java 1.6.4) but putting back to old behaviour + // Anti-cheat: validate spawn protection on the server for mining start. + if (!server->isUnderSpawnProtection(level, x, y, z, player)) player->gameMode->startDestroyBlock(x, y, z, packet->face); else player->connection->send(std::make_shared<TileUpdatePacket>(x, y, z, level)); } @@ -458,8 +504,6 @@ void PlayerConnection::handleUseItem(shared_ptr<UseItemPacket> packet) int face = packet->getFace(); player->resetLastActionTime(); - // 4J Stu - We don't have ops, so just use the levels setting - bool canEditSpawn = level->canEditSpawn; // = level->dimension->id != 0 || server->players->isOp(player->name); if (packet->getFace() == 255) { if (item == nullptr) return; @@ -469,7 +513,8 @@ void PlayerConnection::handleUseItem(shared_ptr<UseItemPacket> packet) { if (synched && player->distanceToSqr(x + 0.5, y + 0.5, z + 0.5) < 8 * 8) { - if (true) // 4J - condition was !server->isUnderSpawnProtection(level, x, y, z, player) (from java 1.6.4) but putting back to old behaviour + // Anti-cheat: block placement/use must pass server-side spawn protection. + if (!server->isUnderSpawnProtection(level, x, y, z, player)) { player->gameMode->useItemOn(player, level, item, x, y, z, face, packet->getClickX(), packet->getClickY(), packet->getClickZ()); } @@ -538,7 +583,18 @@ void PlayerConnection::handleUseItem(shared_ptr<UseItemPacket> packet) void PlayerConnection::onDisconnect(DisconnectPacket::eDisconnectReason reason, void *reasonObjects) { EnterCriticalSection(&done_cs); - if( done ) return; + if( done ) + { + LeaveCriticalSection(&done_cs); + return; + } +#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD) + ServerRuntime::ServerLogManager::OnPlayerDisconnected( + getLogSmallId(), + (player != NULL) ? player->name : std::wstring(), + reason, + false); +#endif // logger.info(player.name + " lost connection: " + reason); // 4J-PB - removed, since it needs to be localised in the language the client is in //server->players->broadcastAll( shared_ptr<ChatPacket>( new ChatPacket(L"�e" + player->name + L" left the game.") ) ); @@ -742,17 +798,16 @@ void PlayerConnection::handleInteract(shared_ptr<InteractPacket> packet) // 4J Stu - If the client says that we hit something, then agree with it. The canSee can fail here as it checks // a ray from head->head, but we may actually be looking at a different part of the entity that can be seen // even though the ray is blocked. - if (target != nullptr) // && player->canSee(target) && player->distanceToSqr(target) < 6 * 6) + if (target != nullptr) { - //boole canSee = player->canSee(target); - //double maxDist = 6 * 6; - //if (!canSee) - //{ - // maxDist = 3 * 3; - //} + // Anti-cheat: enforce reach and LOS on the server to reject forged hits. + bool canSeeTarget = player->canSee(target); + double maxDistSq = canSeeTarget ? kInteractReachSq : kInteractBlockedReachSq; + if (player->distanceToSqr(target) > maxDistSq) + { + return; + } - //if (player->distanceToSqr(target) < maxDist) - //{ if (packet->action == InteractPacket::INTERACT) { player->interact(target); @@ -767,7 +822,6 @@ void PlayerConnection::handleInteract(shared_ptr<InteractPacket> packet) } player->attack(target); } - //} } } diff --git a/Minecraft.Client/PlayerConnection.h b/Minecraft.Client/PlayerConnection.h index ff6093a3..0284bc6a 100644 --- a/Minecraft.Client/PlayerConnection.h +++ b/Minecraft.Client/PlayerConnection.h @@ -37,6 +37,7 @@ private: int dropSpamTickCount; bool m_bHasClientTickedOnce; + unsigned char m_logSmallId; public: PlayerConnection(MinecraftServer *server, Connection *connection, shared_ptr<ServerPlayer> player); @@ -45,6 +46,10 @@ public: void disconnect(DisconnectPacket::eDisconnectReason reason); private: + /** + * Returns the stable network smallId used by dedicated-server logging and refreshes it from the live socket when possible + */ + unsigned char getLogSmallId(); double xLastOk, yLastOk, zLastOk; bool synched; diff --git a/Minecraft.Client/PlayerList.cpp b/Minecraft.Client/PlayerList.cpp index 645e3fb5..ba82ec6a 100644 --- a/Minecraft.Client/PlayerList.cpp +++ b/Minecraft.Client/PlayerList.cpp @@ -37,6 +37,11 @@ #include "Common\Network\Sony\NetworkPlayerSony.h" #endif +#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD) +#include "..\Minecraft.Server\Access\Access.h" +extern bool g_Win64DedicatedServer; +#endif + // 4J - this class is fairly substantially altered as there didn't seem any point in porting code for banning, whitelisting, ops etc. PlayerList::PlayerList(MinecraftServer *server) @@ -1674,6 +1679,13 @@ bool PlayerList::isXuidBanned(PlayerUID xuid) } } +#if defined(_WINDOWS64) && defined(MINECRAFT_SERVER_BUILD) + if (!banned && g_Win64DedicatedServer) + { + banned = ServerRuntime::Access::IsPlayerBanned(xuid); + } +#endif + return banned; } diff --git a/Minecraft.Client/ServerPlayerGameMode.cpp b/Minecraft.Client/ServerPlayerGameMode.cpp index d2dcaaf6..041487f5 100644 --- a/Minecraft.Client/ServerPlayerGameMode.cpp +++ b/Minecraft.Client/ServerPlayerGameMode.cpp @@ -176,31 +176,29 @@ void ServerPlayerGameMode::stopDestroyBlock(int x, int y, int z) { if (x == xDestroyBlock && y == yDestroyBlock && z == zDestroyBlock) { - // int ticksSpentDestroying = gameTicks - destroyProgressStart; - int t = level->getTile(x, y, z); if (t != 0) { Tile *tile = Tile::tiles[t]; - - // MGH - removed checking for the destroy progress here, it has already been checked on the client before it sent the packet. - // fixes issues with this failing to destroy because of packets bunching up - // float destroyProgress = tile->getDestroyProgress(player, player->level, x, y, z) * (ticksSpentDestroying + 1); - // if (destroyProgress >= .7f || bIgnoreDestroyProgress) + // Anti-cheat: re-check destroy progress on the server for STOP_DESTROY. + int ticksSpentDestroying = gameTicks - destroyProgressStart; + float destroyProgress = tile->getDestroyProgress(player, player->level, x, y, z) * (ticksSpentDestroying + 1); + if (destroyProgress >= 1.0f) { isDestroyingBlock = false; level->destroyTileProgress(player->entityId, x, y, z, -1); destroyBlock(x, y, z); } - // else if (!hasDelayedDestroy) - // { - // isDestroyingBlock = false; - // hasDelayedDestroy = true; - // delayedDestroyX = x; - // delayedDestroyY = y; - // delayedDestroyZ = z; - // delayedTickStart = destroyProgressStart; - // } + else if (!hasDelayedDestroy) + { + // Keep server-authoritative mining while allowing legit latency to finish via delayed tick progression. + isDestroyingBlock = false; + hasDelayedDestroy = true; + delayedDestroyX = x; + delayedDestroyY = y; + delayedDestroyZ = z; + delayedTickStart = destroyProgressStart; + } } } } @@ -393,4 +391,4 @@ void ServerPlayerGameMode::setGameRules(GameRulesInstance *rules) { if(m_gameRules != nullptr) delete m_gameRules; m_gameRules = rules; -}
\ No newline at end of file +} diff --git a/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp b/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp index 9d73eda8..981ab3ab 100644 --- a/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp +++ b/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp @@ -8,11 +8,20 @@ #include "WinsockNetLayer.h" #include "..\..\Common\Network\PlatformNetworkManagerStub.h" #include "..\..\..\Minecraft.World\Socket.h" +#if defined(MINECRAFT_SERVER_BUILD) +#include "..\..\..\Minecraft.Server\Access\Access.h" +#include "..\..\..\Minecraft.Server\ServerLogManager.h" +#endif #include "..\..\..\Minecraft.World\DisconnectPacket.h" #include "..\..\Minecraft.h" #include "..\4JLibs\inc\4J_Profile.h" +#include <string> + static bool RecvExact(SOCKET sock, BYTE* buf, int len); +#if defined(MINECRAFT_SERVER_BUILD) +static bool TryGetNumericRemoteIp(const sockaddr_in &remoteAddress, std::string *outIp); +#endif SOCKET WinsockNetLayer::s_listenSocket = INVALID_SOCKET; SOCKET WinsockNetLayer::s_hostConnectionSocket = INVALID_SOCKET; @@ -65,6 +74,7 @@ char g_Win64MultiplayerIP[256] = "127.0.0.1"; bool g_Win64DedicatedServer = false; int g_Win64DedicatedServerPort = WIN64_NET_DEFAULT_PORT; char g_Win64DedicatedServerBindIP[256] = ""; +bool g_Win64DedicatedServerLanAdvertise = true; bool WinsockNetLayer::Initialize() { @@ -90,7 +100,11 @@ bool WinsockNetLayer::Initialize() s_initialized = true; - StartDiscovery(); + // Dedicated Server does not use LAN session discovery and therefore does not initiate discovery. + if (!g_Win64DedicatedServer) + { + StartDiscovery(); + } return true; } @@ -512,6 +526,27 @@ static bool RecvExact(SOCKET sock, BYTE* buf, int len) return true; } +#if defined(MINECRAFT_SERVER_BUILD) +static bool TryGetNumericRemoteIp(const sockaddr_in &remoteAddress, std::string *outIp) +{ + if (outIp == nullptr) + { + return false; + } + + outIp->clear(); + char ipBuffer[64] = {}; + const char *ip = inet_ntop(AF_INET, (void *)&remoteAddress.sin_addr, ipBuffer, sizeof(ipBuffer)); + if (ip == nullptr || ip[0] == 0) + { + return false; + } + + *outIp = ip; + return true; +} +#endif + void WinsockNetLayer::HandleDataReceived(BYTE fromSmallId, BYTE toSmallId, unsigned char* data, unsigned int dataSize) { INetworkPlayer* pPlayerFrom = g_NetworkManager.GetPlayerBySmallId(fromSmallId); @@ -546,7 +581,10 @@ DWORD WINAPI WinsockNetLayer::AcceptThreadProc(LPVOID param) { while (s_active) { - SOCKET clientSocket = accept(s_listenSocket, nullptr, nullptr); + sockaddr_in remoteAddress; + ZeroMemory(&remoteAddress, sizeof(remoteAddress)); + int remoteAddressLength = sizeof(remoteAddress); + SOCKET clientSocket = accept(s_listenSocket, (sockaddr*)&remoteAddress, &remoteAddressLength); if (clientSocket == INVALID_SOCKET) { if (s_active) @@ -557,10 +595,36 @@ DWORD WINAPI WinsockNetLayer::AcceptThreadProc(LPVOID param) int noDelay = 1; setsockopt(clientSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&noDelay, sizeof(noDelay)); +#if defined(MINECRAFT_SERVER_BUILD) + std::string remoteIp; + const bool hasRemoteIp = TryGetNumericRemoteIp(remoteAddress, &remoteIp); + const char *remoteIpForLog = hasRemoteIp ? remoteIp.c_str() : "unknown"; + if (g_Win64DedicatedServer) + { + ServerRuntime::ServerLogManager::OnIncomingTcpConnection(remoteIpForLog); + if (hasRemoteIp && ServerRuntime::Access::IsIpBanned(remoteIp)) + { + ServerRuntime::ServerLogManager::OnRejectedTcpConnection(remoteIpForLog, ServerRuntime::ServerLogManager::eTcpRejectReason_BannedIp); + SendRejectWithReason(clientSocket, DisconnectPacket::eDisconnect_Banned); + closesocket(clientSocket); + continue; + } + } +#endif + extern QNET_STATE _iQNetStubState; if (_iQNetStubState != QNET_STATE_GAME_PLAY) { - app.DebugPrintf("Win64 LAN: Rejecting connection, game not ready\n"); +#if defined(MINECRAFT_SERVER_BUILD) + if (g_Win64DedicatedServer) + { + ServerRuntime::ServerLogManager::OnRejectedTcpConnection(remoteIpForLog, ServerRuntime::ServerLogManager::eTcpRejectReason_GameNotReady); + } + else +#endif + { + app.DebugPrintf("Win64 LAN: Rejecting connection, game not ready\n"); + } closesocket(clientSocket); continue; } @@ -568,7 +632,16 @@ DWORD WINAPI WinsockNetLayer::AcceptThreadProc(LPVOID param) extern CPlatformNetworkManagerStub* g_pPlatformNetworkManager; if (g_pPlatformNetworkManager != nullptr && !g_pPlatformNetworkManager->CanAcceptMoreConnections()) { - app.DebugPrintf("Win64 LAN: Rejecting connection, server at max players\n"); +#if defined(MINECRAFT_SERVER_BUILD) + if (g_Win64DedicatedServer) + { + ServerRuntime::ServerLogManager::OnRejectedTcpConnection(remoteIpForLog, ServerRuntime::ServerLogManager::eTcpRejectReason_ServerFull); + } + else +#endif + { + app.DebugPrintf("Win64 LAN: Rejecting connection, server at max players\n"); + } SendRejectWithReason(clientSocket, DisconnectPacket::eDisconnect_ServerFull); closesocket(clientSocket); continue; @@ -588,7 +661,16 @@ DWORD WINAPI WinsockNetLayer::AcceptThreadProc(LPVOID param) else { LeaveCriticalSection(&s_freeSmallIdLock); - app.DebugPrintf("Win64 LAN: Server full, rejecting connection\n"); +#if defined(MINECRAFT_SERVER_BUILD) + if (g_Win64DedicatedServer) + { + ServerRuntime::ServerLogManager::OnRejectedTcpConnection(remoteIpForLog, ServerRuntime::ServerLogManager::eTcpRejectReason_ServerFull); + } + else +#endif + { + app.DebugPrintf("Win64 LAN: Server full, rejecting connection\n"); + } SendRejectWithReason(clientSocket, DisconnectPacket::eDisconnect_ServerFull); closesocket(clientSocket); continue; @@ -616,7 +698,16 @@ DWORD WINAPI WinsockNetLayer::AcceptThreadProc(LPVOID param) int connIdx = static_cast<int>(s_connections.size()) - 1; LeaveCriticalSection(&s_connectionsLock); - app.DebugPrintf("Win64 LAN: Client connected, assigned smallId=%d\n", assignedSmallId); +#if defined(MINECRAFT_SERVER_BUILD) + if (g_Win64DedicatedServer) + { + ServerRuntime::ServerLogManager::OnAcceptedTcpConnection(assignedSmallId, remoteIpForLog); + } + else +#endif + { + app.DebugPrintf("Win64 LAN: Client connected, assigned smallId=%d\n", assignedSmallId); + } EnterCriticalSection(&s_smallIdToSocketLock); s_smallIdToSocket[assignedSmallId] = clientSocket; diff --git a/Minecraft.Client/Windows64/Network/WinsockNetLayer.h b/Minecraft.Client/Windows64/Network/WinsockNetLayer.h index c5d68975..afccbd66 100644 --- a/Minecraft.Client/Windows64/Network/WinsockNetLayer.h +++ b/Minecraft.Client/Windows64/Network/WinsockNetLayer.h @@ -170,5 +170,6 @@ extern char g_Win64MultiplayerIP[256]; extern bool g_Win64DedicatedServer; extern int g_Win64DedicatedServerPort; extern char g_Win64DedicatedServerBindIP[256]; +extern bool g_Win64DedicatedServerLanAdvertise; #endif |
