diff options
-rw-r--r-- | src/ClientHandle.cpp | 40 | ||||
-rw-r--r-- | src/ClientHandle.h | 4 | ||||
-rw-r--r-- | src/Root.cpp | 18 | ||||
-rw-r--r-- | src/Root.h | 5 | ||||
-rw-r--r-- | src/Server.cpp | 18 | ||||
-rw-r--r-- | src/Server.h | 11 | ||||
-rw-r--r-- | src/World.cpp | 3 | ||||
-rw-r--r-- | src/World.h | 2 |
8 files changed, 96 insertions, 5 deletions
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index c4a620565..cc83bcab3 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -1778,6 +1778,43 @@ void cClientHandle::HandleKeepAlive(int a_KeepAliveID) +bool cClientHandle::CheckMultiLogin(const AString & a_Username) +{ + // If the multilogin is allowed, skip this check entirely: + if ((cRoot::Get()->GetServer()->DoesAllowMultiLogin())) + { + return true; + } + + // Check if the player is waiting to be transferred to the World. + if (cRoot::Get()->GetServer()->IsPlayerInQueue(a_Username)) + { + Kick("A player of the username is already logged in"); + return false; + } + + class cCallback : + public cPlayerListCallback + { + virtual bool Item(cPlayer * a_Player) override + { + return true; + } + } Callback; + + // Check if the player is in any World. + if (cRoot::Get()->DoWithPlayer(a_Username, Callback)) + { + Kick("A player of the username is already logged in"); + return false; + } + return true; +} + + + + + bool cClientHandle::HandleHandshake(const AString & a_Username) { if (!cRoot::Get()->GetPluginManager()->CallHookHandshake(*this, a_Username)) @@ -1788,7 +1825,8 @@ bool cClientHandle::HandleHandshake(const AString & a_Username) return false; } } - return true; + + return CheckMultiLogin(a_Username); } diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 495348ac3..0e588d839 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -280,6 +280,10 @@ public: void HandleEntityLeaveBed (int a_EntityID); void HandleEntitySprinting (int a_EntityID, bool a_IsSprinting); + /** Kicks the current player if the same username is already logged in. + Returns false if a player has been kicked, true otherwise. */ + bool CheckMultiLogin(const AString & a_Username); + /** Called when the protocol handshake has been received (for protocol versions that support it; otherwise the first instant when a username is received). Returns true if the player is to be let in, false if they were disconnected diff --git a/src/Root.cpp b/src/Root.cpp index 865b2a213..29daaedcc 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -196,7 +196,7 @@ void cRoot::Start(void) } #endif - LOG("Startup complete, took %lld ms!", std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - BeginTime).count()); + LOG("Startup complete, took %ld ms!", std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - BeginTime).count()); #ifdef _WIN32 EnableMenuItem(hmenu, SC_CLOSE, MF_ENABLED); // Re-enable close button #endif @@ -643,6 +643,22 @@ bool cRoot::DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallback +bool cRoot::DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback) +{ + for (auto World : m_WorldsByName) + { + if (World.second->DoWithPlayer(a_PlayerName, a_Callback)) + { + return true; + } + } + return false; +} + + + + + AString cRoot::GetProtocolVersionTextFromInt(int a_ProtocolVersion) { return cProtocolRecognizer::GetVersionTextFromInt(a_ProtocolVersion); diff --git a/src/Root.h b/src/Root.h index e70b284f9..2c512a5df 100644 --- a/src/Root.h +++ b/src/Root.h @@ -129,7 +129,10 @@ public: /** Finds the player over his uuid and calls the callback */ bool DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << - + + /** Finds the player using it's complete username and calls the callback */ + bool DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); + // tolua_begin /// Sends a chat message to all connected clients (in all worlds) diff --git a/src/Server.cpp b/src/Server.cpp index d6163df7e..3eaf6e096 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -196,6 +196,7 @@ bool cServer::InitServer(cIniFile & a_SettingsIni, bool a_ShouldAuth) m_Description = a_SettingsIni.GetValueSet("Server", "Description", "MCServer - in C++!"); m_MaxPlayers = a_SettingsIni.GetValueSetI("Server", "MaxPlayers", 100); m_bIsHardcore = a_SettingsIni.GetValueSetB("Server", "HardcoreEnabled", false); + m_bAllowMultiLogin = a_SettingsIni.GetValueSetB("Server", "AllowMultiLogin", false); m_PlayerCount = 0; m_PlayerCountDiff = 0; @@ -298,6 +299,23 @@ int cServer::GetNumPlayers(void) const +bool cServer::IsPlayerInQueue(AString a_Username) +{ + cCSLock Lock(m_CSClients); + for (auto client : m_Clients) + { + if ((client->GetUsername()).compare(a_Username) == 0) + { + return true; + } + } + return false; +} + + + + + void cServer::PrepareKeys(void) { LOGD("Generating protocol encryption keypair..."); diff --git a/src/Server.h b/src/Server.h index 022794bbc..39a5a1a71 100644 --- a/src/Server.h +++ b/src/Server.h @@ -67,6 +67,14 @@ public: // tolua_export int GetNumPlayers(void) const; void SetMaxPlayers(int a_MaxPlayers) { m_MaxPlayers = a_MaxPlayers; } + /** Check if the player is queued to be transferred to a World. + Returns true is Player is found in queue. */ + bool IsPlayerInQueue(AString a_Username); + + /** Can login more than once with same username. + Returns false if it is not allowed, true otherwise. */ + bool DoesAllowMultiLogin(void) { return m_bAllowMultiLogin; } + // Hardcore mode or not: bool IsHardcore(void) const { return m_bIsHardcore; } @@ -216,6 +224,9 @@ private: int m_MaxPlayers; bool m_bIsHardcore; + /** True - allow same username to login more than once False - only once */ + bool m_bAllowMultiLogin; + cTickThread m_TickThread; cEvent m_RestartEvent; diff --git a/src/World.cpp b/src/World.cpp index 633382812..db19649f3 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -743,7 +743,7 @@ void cWorld::InitialiseGeneratorDefaults(cIniFile & a_IniFile) a_IniFile.GetValueSet("Generator", "BiomeGen", "Grown"); a_IniFile.GetValueSet("Generator", "ShapeGen", "BiomalNoise3D"); a_IniFile.GetValueSet("Generator", "CompositionGen", "Biomal"); - a_IniFile.GetValueSet("Generator", "Finishers", "Ravines, WormNestCaves, WaterLakes, WaterSprings, LavaLakes, LavaSprings, OreNests, Mineshafts, Trees, Villages, SprinkleFoliage, Ice, Snow, Lilypads, BottomLava, DeadBushes, PreSimulator, Animals, NaturalPatches"); + a_IniFile.GetValueSet("Generator", "Finishers", "Ravines, WormNestCaves, WaterLakes, WaterSprings, LavaLakes, LavaSprings, OreNests, Mineshafts, Trees, Villages, SprinkleFoliage, Ice, Snow, Lilypads, BottomLava, DeadBushes, NaturalPatches, PreSimulator, Animals"); break; } case dimNether: @@ -3669,3 +3669,4 @@ void cWorld::cChunkGeneratorCallbacks::CallHookChunkGenerated (cChunkDesc & a_Ch + diff --git a/src/World.h b/src/World.h index d64be208e..2f51d60a1 100644 --- a/src/World.h +++ b/src/World.h @@ -808,7 +808,7 @@ public: This function allows nesting and task-concurrency (multiple separate tasks can request ticking and as long as at least one requests is active the chunk will be ticked). */ void SetChunkAlwaysTicked(int a_ChunkX, int a_ChunkZ, bool a_AlwaysTicked = true); // tolua_export - + private: friend class cRoot; |