diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 615039949..7e8c11d67 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -31,6 +31,8 @@
 #include "CompositeChat.h"
 #include "Items/ItemSword.h"
 
+#include "md5/md5.h"
+
 
 
 /** Maximum number of explosions to send this tick, server will start dropping if exceeded */
@@ -175,6 +177,28 @@ void cClientHandle::Destroy(void)
 
 
 
+void cClientHandle::GenerateOfflineUUID(void)
+{
+	// Proper format for a version 3 UUID is:
+	// xxxxxxxx-xxxx-3xxx-yxxx-xxxxxxxxxxxx where x is any hexadecimal digit and y is one of 8, 9, A, or B
+	
+	// Generate an md5 checksum, and use it as base for the ID:
+	MD5 Checksum(m_Username);
+	m_UUID = Checksum.hexdigest();
+	m_UUID[12] = '3';  // Version 3 UUID
+	m_UUID[16] = '8';  // Variant 1 UUID
+	
+	// Now the digest doesn't have the UUID slashes, but the client requires them, so add them into the appropriate positions:
+	m_UUID.insert(8, "-");
+	m_UUID.insert(13, "-");
+	m_UUID.insert(18, "-");
+	m_UUID.insert(23, "-");
+}
+
+
+
+
+
 void cClientHandle::Kick(const AString & a_Reason)
 {
 	if (m_State >= csAuthenticating)  // Don't log pings
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index 0f07c980b..90b971e16 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -63,7 +63,12 @@ public:
 	cPlayer* GetPlayer() { return m_Player; }	// tolua_export
 
 	const AString & GetUUID(void) const { return m_UUID; } // tolua_export
-	void setUUID(const AString & a_UUID) { m_UUID = a_UUID; }
+	void SetUUID(const AString & a_UUID) { m_UUID = a_UUID; }
+	
+	/** Generates an UUID based on the player name provided.
+	This is used for the offline (non-auth) mode, when there's no UUID source.
+	Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same. */
+	void GenerateOfflineUUID(void);
 
 	void Kick(const AString & a_Reason);		// tolua_export
 	void Authenticate(const AString & a_Name, const AString & a_UUID);  // Called by cAuthenticator when the user passes authentication
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index 278b29485..b44c9f919 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -88,8 +88,9 @@ cProtocol172::cProtocol172(cClientHandle * a_Client, const AString & a_ServerAdd
 	// Create the comm log file, if so requested:
 	if (g_ShouldLogCommIn || g_ShouldLogCommOut)
 	{
+		static int sCounter = 0;
 		cFile::CreateFolder("CommLogs");
-		AString FileName = Printf("CommLogs/%x__%s.log", (unsigned)time(NULL), a_Client->GetIPString().c_str());
+		AString FileName = Printf("CommLogs/%x_%d__%s.log", (unsigned)time(NULL), sCounter++, a_Client->GetIPString().c_str());
 		m_CommLogFile.Open(FileName, cFile::fmWrite);
 	}
 }
@@ -796,7 +797,7 @@ void cProtocol172::SendPlayerSpawn(const cPlayer & a_Player)
 	// Called to spawn another player for the client
 	cPacketizer Pkt(*this, 0x0c);  // Spawn Player packet
 	Pkt.WriteVarInt(a_Player.GetUniqueID());
-	Pkt.WriteString(Printf("%d", a_Player.GetUniqueID()));  // TODO: Proper UUID
+	Pkt.WriteString(a_Player.GetClientHandle()->GetUUID());
 	Pkt.WriteString(a_Player.GetName());
 	Pkt.WriteFPInt(a_Player.GetPosX());
 	Pkt.WriteFPInt(a_Player.GetPosY());
@@ -1556,6 +1557,7 @@ void cProtocol172::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffe
 	
 	StartEncryption(DecryptedKey);
 
+	/*
 	// Send login success:
 	{
 		cPacketizer Pkt(*this, 0x02);  // Login success packet
@@ -1565,6 +1567,7 @@ void cProtocol172::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffe
 
 	m_State = 3;  // State = Game
 	m_Client->HandleLogin(4, m_Client->GetUsername());
+	*/
 }
 
 
@@ -1596,10 +1599,13 @@ void cProtocol172::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer)
 		return;
 	}
 	
+	// Generate an offline UUID for the player:
+	m_Client->GenerateOfflineUUID();
+	
 	// Send login success:
 	{
 		cPacketizer Pkt(*this, 0x02);  // Login success packet
-		Pkt.WriteString(Printf("%d", m_Client->GetUniqueID()));  // TODO: proper UUID
+		Pkt.WriteString(m_Client->GetUUID());
 		Pkt.WriteString(Username);
 	}
 
@@ -2773,7 +2779,7 @@ void cProtocol176::SendPlayerSpawn(const cPlayer & a_Player)
 	// Called to spawn another player for the client
 	cPacketizer Pkt(*this, 0x0c);  // Spawn Player packet
 	Pkt.WriteVarInt(a_Player.GetUniqueID());
-	Pkt.WriteString(Printf("00000000-0000-3000-8000-aaaa%08x", a_Player.GetUniqueID()));  // TODO: Proper UUID
+	Pkt.WriteString(a_Player.GetClientHandle()->GetUUID());
 	Pkt.WriteString(a_Player.GetName());
 	Pkt.WriteVarInt(0);  // We have no data to send here
 	Pkt.WriteFPInt(a_Player.GetPosX());