From 61e761fdc2bfa5c77002d68bb24e0470def37b48 Mon Sep 17 00:00:00 2001
From: Vincent <vincent.leung60@gmail.com>
Date: Sat, 29 Nov 2014 00:36:15 -0800
Subject: [PATCH 01/17] issue 1253 - prevent multiple logins with same username

---
 src/ClientHandle.cpp | 18 ++++++++++++++++++
 src/Server.cpp       | 17 +++++++++++++++++
 src/Server.h         |  9 +++++++++
 src/World.cpp        | 12 ++++++++++++
 src/World.h          |  2 ++
 5 files changed, 58 insertions(+)

diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index a6cbad32a..ae794d7cb 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -1798,6 +1798,24 @@ bool cClientHandle::HandleHandshake(const AString & a_Username)
 			return false;
 		}
 	}
+	if (!(cRoot::Get()->GetServer()->isAllowMultiLogin()))
+	{
+		std::list<std::string> usernamesServer = cRoot::Get()->GetServer()->GetUsernames();
+		std::list<std::string> usernamesWorld = cRoot::Get()->GetDefaultWorld()-> GetUsernames();
+		
+		usernamesServer.sort();
+		usernamesWorld.sort();
+		usernamesServer.merge(usernamesWorld);
+		
+		for (std::list<std::string>::iterator itr = usernamesServer.begin(); itr != usernamesServer.end(); ++itr)
+		{
+			if ((*itr).compare(a_Username) == 0)
+			{
+				Kick("User already logged in.");
+				return false;
+			}
+		}
+	}
 	return true;
 }
 
diff --git a/src/Server.cpp b/src/Server.cpp
index bbb5ecff3..157bad43e 100644
--- a/src/Server.cpp
+++ b/src/Server.cpp
@@ -201,6 +201,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;
 
@@ -303,6 +304,22 @@ int cServer::GetNumPlayers(void) const
 
 
 
+std::list<std::string> cServer::GetUsernames()
+{
+	std::list<std::string> usernames;
+	cCSLock Lock(m_CSClients);
+	for (ClientList::iterator itr = m_Clients.begin(); itr != m_Clients.end(); ++itr)
+	{
+		std::string username = (*itr)->GetUsername();
+		usernames.insert(usernames.begin(),username);
+	}
+	return usernames;
+}
+
+
+
+
+
 void cServer::PrepareKeys(void)
 {
 	LOGD("Generating protocol encryption keypair...");
diff --git a/src/Server.h b/src/Server.h
index 022794bbc..91e6e5c45 100644
--- a/src/Server.h
+++ b/src/Server.h
@@ -67,6 +67,12 @@ public:  // tolua_export
 	int  GetNumPlayers(void) const;
 	void SetMaxPlayers(int a_MaxPlayers) { m_MaxPlayers = a_MaxPlayers; }
 	
+	// Get the users waiting to be put into the World.
+	std::list<std::string> GetUsernames(void);
+	
+	// Can login more than once with same username.
+	bool isAllowMultiLogin(void) { return m_bAllowMultiLogin; }
+	
 	// Hardcore mode or not:
 	bool IsHardcore(void) const { return m_bIsHardcore; }
 
@@ -216,6 +222,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 0dec0bd96..9ae9e41d9 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -3666,3 +3666,15 @@ void cWorld::cChunkGeneratorCallbacks::CallHookChunkGenerated (cChunkDesc & a_Ch
 
 
 
+
+std::list<std::string> cWorld::GetUsernames()
+{
+	std::list<std::string> usernames;
+	cCSLock Lock(m_CSPlayers);
+	for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
+	{
+		std::string username = (*itr)->GetName();
+		usernames.insert(usernames.begin(),username);
+	}
+	return usernames;
+}
diff --git a/src/World.h b/src/World.h
index 68d0654ee..81470f869 100644
--- a/src/World.h
+++ b/src/World.h
@@ -808,6 +808,8 @@ public:
 	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
 
+	/** Get the usernames from the World. */
+	std::list<std::string> GetUsernames(void);
 private:
 
 	friend class cRoot;

From a7bf2725c8bd5f8ec3e03584af87a7055cb15a60 Mon Sep 17 00:00:00 2001
From: Vincent <vincent.leung60@gmail.com>
Date: Sat, 29 Nov 2014 11:22:03 -0800
Subject: [PATCH 02/17] fixed naming of strings and changed from i to I

---
 src/ClientHandle.cpp |  8 ++++----
 src/Server.cpp       |  6 +++---
 src/Server.h         |  4 ++--
 src/World.cpp        | 10 +++++++---
 src/World.h          |  3 ++-
 5 files changed, 18 insertions(+), 13 deletions(-)

diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index ae794d7cb..3c06f3401 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -1798,16 +1798,16 @@ bool cClientHandle::HandleHandshake(const AString & a_Username)
 			return false;
 		}
 	}
-	if (!(cRoot::Get()->GetServer()->isAllowMultiLogin()))
+	if (!(cRoot::Get()->GetServer()->IsAllowMultiLogin()))
 	{
-		std::list<std::string> usernamesServer = cRoot::Get()->GetServer()->GetUsernames();
-		std::list<std::string> usernamesWorld = cRoot::Get()->GetDefaultWorld()-> GetUsernames();
+		std::list<AString> usernamesServer = cRoot::Get()->GetServer()->GetUsernames();
+		std::list<AString> usernamesWorld = cRoot::Get()->GetDefaultWorld()-> GetUsernames();
 		
 		usernamesServer.sort();
 		usernamesWorld.sort();
 		usernamesServer.merge(usernamesWorld);
 		
-		for (std::list<std::string>::iterator itr = usernamesServer.begin(); itr != usernamesServer.end(); ++itr)
+		for (std::list<AString>::iterator itr = usernamesServer.begin(); itr != usernamesServer.end(); ++itr)
 		{
 			if ((*itr).compare(a_Username) == 0)
 			{
diff --git a/src/Server.cpp b/src/Server.cpp
index 157bad43e..ed02500ff 100644
--- a/src/Server.cpp
+++ b/src/Server.cpp
@@ -304,13 +304,13 @@ int cServer::GetNumPlayers(void) const
 
 
 
-std::list<std::string> cServer::GetUsernames()
+std::list<AString> cServer::GetUsernames()
 {
-	std::list<std::string> usernames;
+	std::list<AString> usernames;
 	cCSLock Lock(m_CSClients);
 	for (ClientList::iterator itr = m_Clients.begin(); itr != m_Clients.end(); ++itr)
 	{
-		std::string username = (*itr)->GetUsername();
+		AString username = (*itr)->GetUsername();
 		usernames.insert(usernames.begin(),username);
 	}
 	return usernames;
diff --git a/src/Server.h b/src/Server.h
index 91e6e5c45..c9741bb7b 100644
--- a/src/Server.h
+++ b/src/Server.h
@@ -68,10 +68,10 @@ public:  // tolua_export
 	void SetMaxPlayers(int a_MaxPlayers) { m_MaxPlayers = a_MaxPlayers; }
 	
 	// Get the users waiting to be put into the World.
-	std::list<std::string> GetUsernames(void);
+	std::list<AString> GetUsernames(void);
 	
 	// Can login more than once with same username.
-	bool isAllowMultiLogin(void) { return m_bAllowMultiLogin; }
+	bool IsAllowMultiLogin(void) { return m_bAllowMultiLogin; }
 	
 	// Hardcore mode or not:
 	bool IsHardcore(void) const { return m_bIsHardcore; }
diff --git a/src/World.cpp b/src/World.cpp
index 9ae9e41d9..e6a2f161a 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -3667,14 +3667,18 @@ void cWorld::cChunkGeneratorCallbacks::CallHookChunkGenerated (cChunkDesc & a_Ch
 
 
 
-std::list<std::string> cWorld::GetUsernames()
+std::list<AString> cWorld::GetUsernames()
 {
-	std::list<std::string> usernames;
+	std::list<AString> usernames;
 	cCSLock Lock(m_CSPlayers);
 	for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
 	{
-		std::string username = (*itr)->GetName();
+		AString username = (*itr)->GetName();
 		usernames.insert(usernames.begin(),username);
 	}
 	return usernames;
 }
+
+
+
+
diff --git a/src/World.h b/src/World.h
index 81470f869..a3ad4d1da 100644
--- a/src/World.h
+++ b/src/World.h
@@ -809,7 +809,8 @@ public:
 	void SetChunkAlwaysTicked(int a_ChunkX, int a_ChunkZ, bool a_AlwaysTicked = true);  // tolua_export
 
 	/** Get the usernames from the World. */
-	std::list<std::string> GetUsernames(void);
+	std::list<AString> GetUsernames(void);
+	
 private:
 
 	friend class cRoot;

From 72797b14fe5f83a7a27df17d5b733048d13d5d1b Mon Sep 17 00:00:00 2001
From: Vincent <vincent.leung60@gmail.com>
Date: Sat, 29 Nov 2014 15:44:38 -0800
Subject: [PATCH 03/17] Uses callback for players already in World.

---
 src/ClientHandle.cpp | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 3c06f3401..f63754aab 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -1790,6 +1790,7 @@ void cClientHandle::HandleKeepAlive(int a_KeepAliveID)
 
 bool cClientHandle::HandleHandshake(const AString & a_Username)
 {
+
 	if (!cRoot::Get()->GetPluginManager()->CallHookHandshake(*this, a_Username))
 	{
 		if (cRoot::Get()->GetServer()->GetNumPlayers() >= cRoot::Get()->GetServer()->GetMaxPlayers())
@@ -1801,11 +1802,6 @@ bool cClientHandle::HandleHandshake(const AString & a_Username)
 	if (!(cRoot::Get()->GetServer()->IsAllowMultiLogin()))
 	{
 		std::list<AString> usernamesServer = cRoot::Get()->GetServer()->GetUsernames();
-		std::list<AString> usernamesWorld = cRoot::Get()->GetDefaultWorld()-> GetUsernames();
-		
-		usernamesServer.sort();
-		usernamesWorld.sort();
-		usernamesServer.merge(usernamesWorld);
 		
 		for (std::list<AString>::iterator itr = usernamesServer.begin(); itr != usernamesServer.end(); ++itr)
 		{
@@ -1815,6 +1811,17 @@ bool cClientHandle::HandleHandshake(const AString & a_Username)
 				return false;
 			}
 		}
+		class cCallback : public cPlayerListCallback
+		{
+			virtual bool Item(cPlayer * a_Player) override
+			{
+				return false;
+			}
+		} Callback;	
+		if (cRoot::Get()->GetDefaultWorld()->DoWithPlayer(a_Username, Callback))
+		{
+			Kick("User already logged in.");
+		}
 	}
 	return true;
 }

From 20dcceb7e6a8810525fd873f29e665759bdde087 Mon Sep 17 00:00:00 2001
From: Vincent <vincent.leung60@gmail.com>
Date: Sat, 29 Nov 2014 15:46:31 -0800
Subject: [PATCH 04/17] removed GetUsernames() from World

---
 src/World.cpp | 15 ---------------
 src/World.h   |  3 ---
 2 files changed, 18 deletions(-)

diff --git a/src/World.cpp b/src/World.cpp
index e6a2f161a..100df5742 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -3667,18 +3667,3 @@ void cWorld::cChunkGeneratorCallbacks::CallHookChunkGenerated (cChunkDesc & a_Ch
 
 
 
-std::list<AString> cWorld::GetUsernames()
-{
-	std::list<AString> usernames;
-	cCSLock Lock(m_CSPlayers);
-	for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
-	{
-		AString username = (*itr)->GetName();
-		usernames.insert(usernames.begin(),username);
-	}
-	return usernames;
-}
-
-
-
-
diff --git a/src/World.h b/src/World.h
index a3ad4d1da..ee9b93874 100644
--- a/src/World.h
+++ b/src/World.h
@@ -807,9 +807,6 @@ 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
-
-	/** Get the usernames from the World. */
-	std::list<AString> GetUsernames(void);
 	
 private:
 

From 9caa3b19c15b257af47a924c68f9b13517447c26 Mon Sep 17 00:00:00 2001
From: vincentleung1 <vincent.leung60@gmail.com>
Date: Sat, 29 Nov 2014 15:59:48 -0800
Subject: [PATCH 05/17] removed extra space and fixed some formatting in
 cCallback

---
 src/ClientHandle.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index f63754aab..54a39cdc2 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -1790,7 +1790,6 @@ void cClientHandle::HandleKeepAlive(int a_KeepAliveID)
 
 bool cClientHandle::HandleHandshake(const AString & a_Username)
 {
-
 	if (!cRoot::Get()->GetPluginManager()->CallHookHandshake(*this, a_Username))
 	{
 		if (cRoot::Get()->GetServer()->GetNumPlayers() >= cRoot::Get()->GetServer()->GetMaxPlayers())
@@ -1811,11 +1810,12 @@ bool cClientHandle::HandleHandshake(const AString & a_Username)
 				return false;
 			}
 		}
-		class cCallback : public cPlayerListCallback
+		class cCallback :
+		public cPlayerListCallback
 		{
 			virtual bool Item(cPlayer * a_Player) override
 			{
-				return false;
+				return true;
 			}
 		} Callback;	
 		if (cRoot::Get()->GetDefaultWorld()->DoWithPlayer(a_Username, Callback))

From 438a9b04cbabcbbab06d9f5bd00ced3342eb97f8 Mon Sep 17 00:00:00 2001
From: vincentleung1 <vincent.leung60@gmail.com>
Date: Sat, 29 Nov 2014 16:05:22 -0800
Subject: [PATCH 06/17] Changed Kick message

---
 src/ClientHandle.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 54a39cdc2..1ffb5f04b 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -1806,7 +1806,7 @@ bool cClientHandle::HandleHandshake(const AString & a_Username)
 		{
 			if ((*itr).compare(a_Username) == 0)
 			{
-				Kick("User already logged in.");
+				Kick("A player of the username is already logged in");
 				return false;
 			}
 		}
@@ -1820,7 +1820,7 @@ bool cClientHandle::HandleHandshake(const AString & a_Username)
 		} Callback;	
 		if (cRoot::Get()->GetDefaultWorld()->DoWithPlayer(a_Username, Callback))
 		{
-			Kick("User already logged in.");
+			Kick("A player of the username is already logged in");
 		}
 	}
 	return true;

From 8edfd7829505d43c7d6bf7fcc582e0d7cb29e1d5 Mon Sep 17 00:00:00 2001
From: Vincent <vincent.leung60@gmail.com>
Date: Sun, 7 Dec 2014 12:41:42 -0800
Subject: [PATCH 07/17] changed from using iterator to auto for server and
 clienthandle

---
 src/ClientHandle.cpp | 4 ++--
 src/Server.cpp       | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index f63754aab..94126d496 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -1803,9 +1803,9 @@ bool cClientHandle::HandleHandshake(const AString & a_Username)
 	{
 		std::list<AString> usernamesServer = cRoot::Get()->GetServer()->GetUsernames();
 		
-		for (std::list<AString>::iterator itr = usernamesServer.begin(); itr != usernamesServer.end(); ++itr)
+		for (auto item : usernamesServer)
 		{
-			if ((*itr).compare(a_Username) == 0)
+			if ((item).compare(a_Username) == 0)
 			{
 				Kick("User already logged in.");
 				return false;
diff --git a/src/Server.cpp b/src/Server.cpp
index ed02500ff..15c9521b9 100644
--- a/src/Server.cpp
+++ b/src/Server.cpp
@@ -308,9 +308,9 @@ std::list<AString> cServer::GetUsernames()
 {
 	std::list<AString> usernames;
 	cCSLock Lock(m_CSClients);
-	for (ClientList::iterator itr = m_Clients.begin(); itr != m_Clients.end(); ++itr)
+	for (auto client : m_Clients)
 	{
-		AString username = (*itr)->GetUsername();
+		AString username = (client)->GetUsername();
 		usernames.insert(usernames.begin(),username);
 	}
 	return usernames;

From d8d3b9aec5bbb0f6d632d86f1fb7b1e8f58e9063 Mon Sep 17 00:00:00 2001
From: Vincent <vincent.leung60@gmail.com>
Date: Mon, 8 Dec 2014 00:12:48 -0800
Subject: [PATCH 08/17] Moved the check into a new function and just calls that
 function and a blank FindAndDoWithPlayer added.

---
 src/ClientHandle.cpp | 60 ++++++++++++++++++++++++++++----------------
 src/ClientHandle.h   |  2 ++
 src/Root.cpp         |  9 +++++++
 src/Root.h           |  4 ++-
 4 files changed, 52 insertions(+), 23 deletions(-)

diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 3fca48394..025588485 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -1788,6 +1788,41 @@ void cClientHandle::HandleKeepAlive(int a_KeepAliveID)
 
 
 
+bool cClientHandle::CheckMultiLogin(void)
+{
+	std::list<AString> usernamesServer = cRoot::Get()->GetServer()->GetUsernames();
+	
+	for (auto item : usernamesServer)
+	{
+		if ((item).compare(a_Username) == 0)
+		{
+			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;	
+	
+	if (cRoot::Get()->GetDefaultWorld()->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))
@@ -1798,31 +1833,12 @@ bool cClientHandle::HandleHandshake(const AString & a_Username)
 			return false;
 		}
 	}
+	
 	if (!(cRoot::Get()->GetServer()->IsAllowMultiLogin()))
 	{
-		std::list<AString> usernamesServer = cRoot::Get()->GetServer()->GetUsernames();
-		
-		for (auto item : usernamesServer)
-		{
-			if ((item).compare(a_Username) == 0)
-			{
-				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;	
-		if (cRoot::Get()->GetDefaultWorld()->DoWithPlayer(a_Username, Callback))
-		{
-			Kick("A player of the username is already logged in");
-		}
+		return CheckMultiLogin();
 	}
+	
 	return true;
 }
 
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index f195b6be7..880a404da 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -280,6 +280,8 @@ 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. */
+	bool CheckMultiLogin(void);
 	/** 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 e309bb174..e51b7a048 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -649,6 +649,15 @@ bool cRoot::DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallback
 
 
 
+bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback)
+{
+	
+}
+
+
+
+
+
 AString cRoot::GetProtocolVersionTextFromInt(int a_ProtocolVersion)
 {
 	return cProtocolRecognizer::GetVersionTextFromInt(a_ProtocolVersion);
diff --git a/src/Root.h b/src/Root.h
index 29753a47d..b926b36bc 100644
--- a/src/Root.h
+++ b/src/Root.h
@@ -128,7 +128,9 @@ public:
 
 	/** Finds the player over his uuid and calls the callback */
 	bool DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallback & a_Callback);  // >> EXPORTED IN MANUALBINDINGS <<
-
+	
+	bool FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback);
+	
 	// tolua_begin
 	
 	/// Sends a chat message to all connected clients (in all worlds)

From ed09e76023436c9414356921bc761618b3bb9341 Mon Sep 17 00:00:00 2001
From: Vincent <vincent.leung60@gmail.com>
Date: Mon, 8 Dec 2014 00:16:09 -0800
Subject: [PATCH 09/17] Changed HandleHandshake to return the result of
 CheckMultiLogin instead of just true since it already returns true if it
 finds and kicks the current player.

---
 src/ClientHandle.cpp | 49 ++++++++++++++++++++++----------------------
 1 file changed, 24 insertions(+), 25 deletions(-)

diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 025588485..e60bb5373 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -1790,32 +1790,35 @@ void cClientHandle::HandleKeepAlive(int a_KeepAliveID)
 
 bool cClientHandle::CheckMultiLogin(void)
 {
-	std::list<AString> usernamesServer = cRoot::Get()->GetServer()->GetUsernames();
-	
-	for (auto item : usernamesServer)
+	if (!(cRoot::Get()->GetServer()->IsAllowMultiLogin()))
 	{
-		if ((item).compare(a_Username) == 0)
+		std::list<AString> usernamesServer = cRoot::Get()->GetServer()->GetUsernames();
+	
+		for (auto item : usernamesServer)
+		{
+			if ((item).compare(a_Username) == 0)
+			{
+				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;	
+	
+		if (cRoot::Get()->GetDefaultWorld()->DoWithPlayer(a_Username, Callback))
 		{
 			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;	
-	
-	if (cRoot::Get()->GetDefaultWorld()->DoWithPlayer(a_Username, Callback))
-	{
-		Kick("A player of the username is already logged in");
-		return false;
-	}
-	
 	return true;
 }
 
@@ -1833,13 +1836,9 @@ bool cClientHandle::HandleHandshake(const AString & a_Username)
 			return false;
 		}
 	}
+
+	return CheckMultiLogin();
 	
-	if (!(cRoot::Get()->GetServer()->IsAllowMultiLogin()))
-	{
-		return CheckMultiLogin();
-	}
-	
-	return true;
 }
 
 

From 656964dc385e4460215d2443724f322cd1bc596d Mon Sep 17 00:00:00 2001
From: Vincent <vincent.leung60@gmail.com>
Date: Mon, 8 Dec 2014 00:19:33 -0800
Subject: [PATCH 10/17] removed last space in handlehandshake

---
 src/ClientHandle.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index e60bb5373..4031fa1df 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -1838,7 +1838,6 @@ bool cClientHandle::HandleHandshake(const AString & a_Username)
 	}
 
 	return CheckMultiLogin();
-	
 }
 
 

From 6de07d4a39096f19c075695824aa87a1907e4edc Mon Sep 17 00:00:00 2001
From: Vincent <vincent.leung60@gmail.com>
Date: Mon, 8 Dec 2014 00:45:29 -0800
Subject: [PATCH 11/17] Fixed compile errors

---
 src/ClientHandle.cpp | 11 +++--------
 src/ClientHandle.h   |  2 +-
 src/Root.cpp         |  2 +-
 src/Root.h           |  2 +-
 src/Server.cpp       | 11 ++++++-----
 src/Server.h         |  4 ++--
 6 files changed, 14 insertions(+), 18 deletions(-)

diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 4031fa1df..6f7bd1faf 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -1788,19 +1788,14 @@ void cClientHandle::HandleKeepAlive(int a_KeepAliveID)
 
 
 
-bool cClientHandle::CheckMultiLogin(void)
+bool cClientHandle::CheckMultiLogin(const AString & a_Username)
 {
 	if (!(cRoot::Get()->GetServer()->IsAllowMultiLogin()))
 	{
-		std::list<AString> usernamesServer = cRoot::Get()->GetServer()->GetUsernames();
-	
-		for (auto item : usernamesServer)
+		if (cRoot::Get()->GetServer()->IsPlayerInQueue(a_Username))
 		{
-			if ((item).compare(a_Username) == 0)
-			{
 				Kick("A player of the username is already logged in");
 				return false;
-			}
 		}
 	
 		class cCallback :
@@ -1837,7 +1832,7 @@ bool cClientHandle::HandleHandshake(const AString & a_Username)
 		}
 	}
 
-	return CheckMultiLogin();
+	return CheckMultiLogin(a_Username);
 }
 
 
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index 880a404da..add004bd5 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -281,7 +281,7 @@ public:
 	void HandleEntitySprinting        (int a_EntityID, bool a_IsSprinting);
 	
 	/** Kicks the current player if the same username is already logged in. */
-	bool CheckMultiLogin(void);
+	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 e51b7a048..dddb943a2 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -649,7 +649,7 @@ bool cRoot::DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallback
 
 
 
-bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback)
+bool cRoot::DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback)
 {
 	
 }
diff --git a/src/Root.h b/src/Root.h
index b926b36bc..b3cde8748 100644
--- a/src/Root.h
+++ b/src/Root.h
@@ -129,7 +129,7 @@ public:
 	/** Finds the player over his uuid and calls the callback */
 	bool DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallback & a_Callback);  // >> EXPORTED IN MANUALBINDINGS <<
 	
-	bool FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback);
+	bool DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback);
 	
 	// tolua_begin
 	
diff --git a/src/Server.cpp b/src/Server.cpp
index 15c9521b9..a1dd27c57 100644
--- a/src/Server.cpp
+++ b/src/Server.cpp
@@ -304,16 +304,17 @@ int cServer::GetNumPlayers(void) const
 
 
 
-std::list<AString> cServer::GetUsernames()
+bool cServer::IsPlayerInQueue(AString a_Username)
 {
-	std::list<AString> usernames;
 	cCSLock Lock(m_CSClients);
 	for (auto client : m_Clients)
 	{
-		AString username = (client)->GetUsername();
-		usernames.insert(usernames.begin(),username);
+		if ((client->GetUsername()).compare(a_Username) == 0)
+		{
+			return true;
+		}
 	}
-	return usernames;
+	return false;
 }
 
 
diff --git a/src/Server.h b/src/Server.h
index c9741bb7b..e329b5c65 100644
--- a/src/Server.h
+++ b/src/Server.h
@@ -67,8 +67,8 @@ public:  // tolua_export
 	int  GetNumPlayers(void) const;
 	void SetMaxPlayers(int a_MaxPlayers) { m_MaxPlayers = a_MaxPlayers; }
 	
-	// Get the users waiting to be put into the World.
-	std::list<AString> GetUsernames(void);
+	// Check if the player is queued to be transferred to a World.
+	bool IsPlayerInQueue(AString a_Username);
 	
 	// Can login more than once with same username.
 	bool IsAllowMultiLogin(void) { return m_bAllowMultiLogin; }

From e28cc876c4aa4d71f821fca45b5486b8ef6cca4e Mon Sep 17 00:00:00 2001
From: Vincent <vincent.leung60@gmail.com>
Date: Mon, 8 Dec 2014 00:57:46 -0800
Subject: [PATCH 12/17] created callback in Root and changed CheckMultiLogin()
 to use the DoWithPlayer function at Root instead of World.

---
 src/ClientHandle.cpp | 2 +-
 src/Root.cpp         | 9 ++++++++-
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 6f7bd1faf..6fe7cbd4a 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -1807,7 +1807,7 @@ bool cClientHandle::CheckMultiLogin(const AString & a_Username)
 			}
 		} Callback;	
 	
-		if (cRoot::Get()->GetDefaultWorld()->DoWithPlayer(a_Username, Callback))
+		if (cRoot::Get()->DoWithPlayer(a_Username, Callback))
 		{
 			Kick("A player of the username is already logged in");
 			return false;
diff --git a/src/Root.cpp b/src/Root.cpp
index dddb943a2..c59590d95 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -651,7 +651,14 @@ bool cRoot::DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallback
 
 bool cRoot::DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback)
 {
-	
+	for (WorldMap::iterator itr = m_WorldsByName.begin(); itr != m_WorldsByName.end(); itr++)
+	{
+		if (itr->second->DoWithPlayer(a_PlayerName, a_Callback))
+		{
+			return true;
+		}
+	}
+	return false;
 }
 
 

From 12c012fa01e719c7c103e36ae0407294a0d11bfb Mon Sep 17 00:00:00 2001
From: Vincent <vincent.leung60@gmail.com>
Date: Mon, 8 Dec 2014 14:33:59 -0800
Subject: [PATCH 13/17] Changed CheckMultiLogin() to not have main body wrapped
 in an if statement. Added in indent to cPlayerListCallBack in cCallback class
 inside CheckMultiLogin(). Added doxy-comment for DoWithPlayer(). Changed
 comments on IsPlayerInQueue() and IsAllowMultiLogin() to doxy-comments.

---
 src/ClientHandle.cpp | 47 +++++++++++++++++++++++---------------------
 src/ClientHandle.h   |  1 +
 src/Root.h           |  1 +
 src/Server.h         |  6 ++++--
 4 files changed, 31 insertions(+), 24 deletions(-)

diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 6fe7cbd4a..3bc17d1a9 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -1790,31 +1790,34 @@ void cClientHandle::HandleKeepAlive(int a_KeepAliveID)
 
 bool cClientHandle::CheckMultiLogin(const AString & a_Username)
 {
-	if (!(cRoot::Get()->GetServer()->IsAllowMultiLogin()))
+	// If the multilogin is allowed, skip this check entirely:
+	if ((cRoot::Get()->GetServer()->IsAllowMultiLogin()))
 	{
-		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;	
-	
-		if (cRoot::Get()->DoWithPlayer(a_Username, Callback))
-		{
-			Kick("A player of the username is already logged in");
-			return false;
-		}
+		return true;
 	}
 	
-	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;
+	}
 }
 
 
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index add004bd5..cd63aa308 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -282,6 +282,7 @@ public:
 	
 	/** Kicks the current player if the same username is already logged in. */
 	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.h b/src/Root.h
index b3cde8748..af5a2b47b 100644
--- a/src/Root.h
+++ b/src/Root.h
@@ -129,6 +129,7 @@ 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
diff --git a/src/Server.h b/src/Server.h
index e329b5c65..a93e8df75 100644
--- a/src/Server.h
+++ b/src/Server.h
@@ -67,10 +67,12 @@ 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.
+	/** 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.
+	/** Can login more than once with same username. 
+		Returns false if it is not allowed, true otherwise. */
 	bool IsAllowMultiLogin(void) { return m_bAllowMultiLogin; }
 	
 	// Hardcore mode or not:

From e9a27db028172b5d964cee4421ed5df3af5a1cf0 Mon Sep 17 00:00:00 2001
From: Vincent <vincent.leung60@gmail.com>
Date: Mon, 8 Dec 2014 15:58:46 -0800
Subject: [PATCH 14/17] Changed DoWithPlayer to auto instead of using iterator.

---
 src/Root.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/Root.cpp b/src/Root.cpp
index c59590d95..2234f7fdc 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -651,9 +651,9 @@ bool cRoot::DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallback
 
 bool cRoot::DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback)
 {
-	for (WorldMap::iterator itr = m_WorldsByName.begin(); itr != m_WorldsByName.end(); itr++)
+	for (auto World : m_WorldsByName)
 	{
-		if (itr->second->DoWithPlayer(a_PlayerName, a_Callback))
+		if (World.second->DoWithPlayer(a_PlayerName, a_Callback))
 		{
 			return true;
 		}

From 4b08ca261bed5ec2fd70f64ee96104ba6bee6927 Mon Sep 17 00:00:00 2001
From: Vincent <vincent.leung60@gmail.com>
Date: Tue, 9 Dec 2014 03:06:25 -0800
Subject: [PATCH 15/17] Fixed indent problems and added return definitions to
 CheckMultiLogin(). Changed from IsAllowMultiLogin() to DoesAllowMultiLogin().
 Fixed CheckMultiLogin() to not run to the end without returning a value.

---
 src/ClientHandle.cpp | 6 +++---
 src/ClientHandle.h   | 3 ++-
 src/Server.h         | 6 +++---
 3 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 3bc17d1a9..6812c06ac 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -1799,8 +1799,8 @@ bool cClientHandle::CheckMultiLogin(const AString & a_Username)
 	// 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;
+		Kick("A player of the username is already logged in");
+		return false;
 	}
 
 	class cCallback :
@@ -1816,8 +1816,8 @@ bool cClientHandle::CheckMultiLogin(const AString & a_Username)
 	if (cRoot::Get()->DoWithPlayer(a_Username, Callback))
 	{
 		Kick("A player of the username is already logged in");
-		return false;
 	}
+	return false;
 }
 
 
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index cd63aa308..b3aec86f6 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -280,7 +280,8 @@ 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. */
+	/** 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;
diff --git a/src/Server.h b/src/Server.h
index a93e8df75..39a5a1a71 100644
--- a/src/Server.h
+++ b/src/Server.h
@@ -68,12 +68,12 @@ public:  // tolua_export
 	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. */
+	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 IsAllowMultiLogin(void) { return m_bAllowMultiLogin; }
+	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; }

From 3a2759fdc1a2c7282bd90a1f545fa1effae2728b Mon Sep 17 00:00:00 2001
From: Vincent <vincent.leung60@gmail.com>
Date: Tue, 9 Dec 2014 14:23:44 -0800
Subject: [PATCH 16/17] Fixed return value in CheckMultiLogin()

---
 src/ClientHandle.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 6812c06ac..87dc27f8f 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -1816,8 +1816,9 @@ bool cClientHandle::CheckMultiLogin(const AString & a_Username)
 	if (cRoot::Get()->DoWithPlayer(a_Username, Callback))
 	{
 		Kick("A player of the username is already logged in");
+		return false;
 	}
-	return false;
+	return true;
 }
 
 

From 9bba8e4c7d88c0769bb7643a2a8b577a3d12c1af Mon Sep 17 00:00:00 2001
From: Vincent <vincent.leung60@gmail.com>
Date: Wed, 10 Dec 2014 00:45:24 -0800
Subject: [PATCH 17/17] Changed method call to DoesAllowMultiLogin() instead of
 IsAllowMultiLogin() Compiles correctly.

---
 src/ClientHandle.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 87dc27f8f..8a39c3ecb 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -1791,7 +1791,7 @@ 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()->IsAllowMultiLogin()))
+	if ((cRoot::Get()->GetServer()->DoesAllowMultiLogin()))
 	{
 		return true;
 	}