summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Bindings/AllToLua.pkg9
-rw-r--r--src/Bindings/CMakeLists.txt1
-rw-r--r--src/Bindings/LuaState.cpp76
-rw-r--r--src/Bindings/LuaState.h5
-rw-r--r--src/Bindings/ManualBindings.cpp285
-rw-r--r--src/Bindings/ManualBindings_RankManager.cpp71
-rw-r--r--src/Bindings/ManualBindings_World.cpp50
-rw-r--r--src/BlockEntities/MobHeadEntity.cpp5
-rw-r--r--src/BlockEntities/MobHeadEntity.h18
-rw-r--r--src/ByteBuffer.cpp24
-rw-r--r--src/ByteBuffer.h4
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/ClientHandle.cpp41
-rw-r--r--src/ClientHandle.h28
-rw-r--r--src/Entities/Player.cpp13
-rw-r--r--src/Entities/Player.h16
-rw-r--r--src/Mobs/Ocelot.h7
-rw-r--r--src/Mobs/Wolf.cpp2
-rw-r--r--src/Mobs/Wolf.h15
-rw-r--r--src/Protocol/Authenticator.cpp13
-rw-r--r--src/Protocol/Authenticator.h8
-rw-r--r--src/Protocol/MojangAPI.cpp192
-rw-r--r--src/Protocol/MojangAPI.h50
-rw-r--r--src/Protocol/Packetizer.cpp53
-rw-r--r--src/Protocol/Packetizer.h6
-rw-r--r--src/Protocol/Protocol_1_10.cpp2
-rw-r--r--src/Protocol/Protocol_1_11.cpp2
-rw-r--r--src/Protocol/Protocol_1_8.cpp15
-rw-r--r--src/Protocol/Protocol_1_9.cpp14
-rw-r--r--src/RankManager.cpp86
-rw-r--r--src/RankManager.h28
-rw-r--r--src/Root.cpp4
-rw-r--r--src/Root.h5
-rw-r--r--src/Server.cpp2
-rw-r--r--src/Server.h3
-rw-r--r--src/UUID.cpp283
-rw-r--r--src/UUID.h100
-rw-r--r--src/World.cpp5
-rw-r--r--src/World.h5
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp11
-rwxr-xr-xsrc/WorldStorage/WSSAnvil.cpp35
-rwxr-xr-xsrc/WorldStorage/WSSAnvil.h5
42 files changed, 1116 insertions, 483 deletions
diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg
index b99ac2f88..778cdf42c 100644
--- a/src/Bindings/AllToLua.pkg
+++ b/src/Bindings/AllToLua.pkg
@@ -17,13 +17,15 @@ inheritance doesn't work properly (#1789).
$#include "../Globals.h"
// Typedefs from Globals.h, so that we don't have to process that file:
-typedef long long Int64;
-typedef int Int32;
-typedef short Int16;
+typedef signed long long Int64;
+typedef signed int Int32;
+typedef signed short Int16;
+typedef signed char Int8;
typedef unsigned long long UInt64;
typedef unsigned int UInt32;
typedef unsigned short UInt16;
+typedef unsigned char UInt8;
$cfile "../Vector3.h"
@@ -69,6 +71,7 @@ $cfile "../MapManager.h"
$cfile "../Scoreboard.h"
$cfile "../Statistics.h"
$cfile "../Protocol/MojangAPI.h"
+$cfile "../UUID.h"
// Entities:
$cfile "../Entities/Entity.h"
diff --git a/src/Bindings/CMakeLists.txt b/src/Bindings/CMakeLists.txt
index 6b2ad7ab0..0ab21467b 100644
--- a/src/Bindings/CMakeLists.txt
+++ b/src/Bindings/CMakeLists.txt
@@ -139,6 +139,7 @@ set(BINDING_DEPENDENCIES
../StringUtils.h
../Tracer.h
../UI/Window.h
+ ../UUID.h
../Vector3.h
../WebAdmin.h
../World.h
diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp
index b443325ec..7bd4becb6 100644
--- a/src/Bindings/LuaState.cpp
+++ b/src/Bindings/LuaState.cpp
@@ -20,6 +20,7 @@ extern "C"
#include "../Entities/Entity.h"
#include "../BlockEntities/BlockEntity.h"
#include "../DeadlockDetect.h"
+#include "../UUID.h"
@@ -1410,6 +1411,40 @@ bool cLuaState::GetStackValue(int a_StackPos, float & a_ReturnedVal)
+bool cLuaState::GetStackValue(int a_StackPos, cUUID & a_Value)
+{
+ if (lua_isnil(m_LuaState, a_StackPos))
+ {
+ return false;
+ }
+
+ tolua_Error tolua_Err;
+ if (tolua_isusertype(m_LuaState, a_StackPos, "cUUID", 0, &tolua_Err))
+ {
+ // Found a cUUID, copy into output value
+ cUUID * PtrUUID = nullptr;
+ GetStackValue(a_StackPos, PtrUUID);
+ if (PtrUUID == nullptr)
+ {
+ return false;
+ }
+ a_Value = *PtrUUID;
+ return true;
+ }
+
+ // Try to get a string and parse as a UUID into the output
+ AString StrUUID;
+ if (!GetStackValue(a_StackPos, StrUUID))
+ {
+ return false;
+ }
+ return a_Value.FromString(StrUUID);
+}
+
+
+
+
+
cLuaState::cStackValue cLuaState::WalkToValue(const AString & a_Name)
{
// There needs to be at least one value on the stack:
@@ -1785,6 +1820,47 @@ bool cLuaState::CheckParamFunctionOrNil(int a_StartParam, int a_EndParam)
+bool cLuaState::CheckParamUUID(int a_StartParam, int a_EndParam)
+{
+ ASSERT(IsValid());
+
+ if (a_EndParam < 0)
+ {
+ a_EndParam = a_StartParam;
+ }
+
+ cUUID tempUUID;
+ AString tempStr;
+ // Accept either a cUUID or a string that contains a valid UUID
+ for (int i = a_StartParam; i <= a_EndParam; ++i)
+ {
+ tolua_Error err;
+ if (tolua_isusertype(m_LuaState, i, "cUUID", 0, &err) && !lua_isnil(m_LuaState, i))
+ {
+ continue;
+ }
+
+ if (!tolua_iscppstring(m_LuaState, i, 0, &err))
+ {
+ ApiParamError("Failed to read parameter #%d. UUID expected, got %s", i, GetTypeText(i).c_str());
+ return false;
+ }
+
+ // Check string is a valid UUID
+ GetStackValue(i, tempStr);
+ if (!tempUUID.FromString(tempStr))
+ {
+ ApiParamError("Failed to read parameter #%d. UUID expected, got non-UUID string:\n\t\"%s\"", i, tempStr.c_str());
+ return false;
+ }
+ }
+ return true;
+}
+
+
+
+
+
bool cLuaState::CheckParamEnd(int a_Param)
{
tolua_Error tolua_err;
diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h
index 8014f40d4..98f1cbc28 100644
--- a/src/Bindings/LuaState.h
+++ b/src/Bindings/LuaState.h
@@ -659,6 +659,7 @@ public:
bool GetStackValue(int a_StackPos, eBlockFace & a_Value);
bool GetStackValue(int a_StackPos, eWeather & a_Value);
bool GetStackValue(int a_StackPos, float & a_ReturnedVal);
+ bool GetStackValue(int a_StackPos, cUUID & a_Value);
// template to catch all of the various c++ integral types without overload conflicts
template <class T>
@@ -787,6 +788,10 @@ public:
/** Returns true if the specified parameters on the stack are functions or nils; also logs warning if not */
bool CheckParamFunctionOrNil(int a_StartParam, int a_EndParam = -1);
+ /** Returns true if the specified parameters on the stack are UUIDs; also logs warning if not
+ Accepts either cUUID instances or strings that contain UUIDs */
+ bool CheckParamUUID(int a_StartParam, int a_EndParam = -1);
+
/** Returns true if the specified parameter on the stack is nil (indicating an end-of-parameters) */
bool CheckParamEnd(int a_Param);
diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp
index 6fe133e1e..c87e9ed20 100644
--- a/src/Bindings/ManualBindings.cpp
+++ b/src/Bindings/ManualBindings.cpp
@@ -1665,6 +1665,28 @@ static int tolua_cPlayer_PermissionMatches(lua_State * tolua_S)
+static int tolua_cPlayer_GetUUID(lua_State * tolua_S)
+{
+ // Check the params:
+ cLuaState L(tolua_S);
+ if (!L.CheckParamSelf("cPlayer"))
+ {
+ return 0;
+ }
+
+ // Get the params:
+ cPlayer * Self = nullptr;
+ L.GetStackValue(1, Self);
+
+ // Return the UUID as a string
+ L.Push(Self->GetUUID().ToShortString());
+ return 1;
+}
+
+
+
+
+
template <
class OBJTYPE,
void (OBJTYPE::*SetCallback)(cLuaState::cCallbackPtr && a_CallbackFn)
@@ -2318,7 +2340,7 @@ static int tolua_cClientHandle_SendPluginMessage(lua_State * L)
{
cLuaState S(L);
if (
- !S.CheckParamUserType(1, "cClientHandle") ||
+ !S.CheckParamSelf("cClientHandle") ||
!S.CheckParamString(2, 3) ||
!S.CheckParamEnd(4)
)
@@ -2343,13 +2365,145 @@ static int tolua_cClientHandle_SendPluginMessage(lua_State * L)
+static int tolua_cClientHandle_GetUUID(lua_State * tolua_S)
+{
+ // Check the params:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamSelf("cClientHandle") ||
+ !L.CheckParamEnd(2)
+ )
+ {
+ return 0;
+ }
+
+ // Get the params:
+ cClientHandle * Self;
+ L.GetStackValue(1, Self);
+
+ // Return the UUID as a string:
+ L.Push(Self->GetUUID().ToShortString());
+ return 1;
+}
+
+
+
+
+
+static int tolua_cClientHandle_GenerateOfflineUUID(lua_State * tolua_S)
+{
+ // Check the params:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamStaticSelf("cClientHandle") ||
+ !L.CheckParamString(2) ||
+ !L.CheckParamEnd(3)
+ )
+ {
+ return 0;
+ }
+
+ // Get the params:
+ AString Username;
+ L.GetStackValue(2, Username);
+
+ // Return the UUID as a string:
+ L.Push(cClientHandle::GenerateOfflineUUID(Username).ToShortString());
+ return 1;
+}
+
+
+
+
+
+static int tolua_cClientHandle_IsUUIDOnline(lua_State * tolua_S)
+{
+ // Check the params:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamStaticSelf("cClientHandle") ||
+ !L.CheckParamUUID(2) ||
+ !L.CheckParamEnd(3)
+ )
+ {
+ return 0;
+ }
+
+ // Get the params:
+ cUUID UUID;
+ L.GetStackValue(2, UUID);
+
+ // Return the result:
+ L.Push(cClientHandle::IsUUIDOnline(UUID));
+ return 1;
+}
+
+
+
+
+static int tolua_cMobHeadEntity_SetOwner(lua_State * tolua_S)
+{
+ // Check params:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamSelf("cMobHeadEntity") ||
+ !L.CheckParamUUID(2) ||
+ !L.CheckParamString(3, 5) ||
+ !L.CheckParamEnd(6)
+ )
+ {
+ return 0;
+ }
+
+
+ // Get the params:
+ cMobHeadEntity * Self;
+ cUUID OwnerUUID;
+ AString OwnerName, OwnerTexture, OwnerTextureSignature;
+ L.GetStackValues(1, Self, OwnerUUID, OwnerName, OwnerTexture, OwnerTextureSignature);
+
+ // Set the owner:
+ Self->SetOwner(OwnerUUID, OwnerName, OwnerTexture, OwnerTextureSignature);
+ return 0;
+}
+
+
+
+
+
+static int tolua_cMobHeadEntity_GetOwnerUUID(lua_State * tolua_S)
+{
+ // Check params:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamSelf("cMobHeadEntity") ||
+ !L.CheckParamEnd(2)
+ )
+ {
+ return 0;
+ }
+
+ // Get the params:
+ cMobHeadEntity * Self;
+ L.GetStackValue(1, Self);
+
+ // Return the UUID as a string:
+ cUUID Owner = Self->GetOwnerUUID();
+ L.Push(Owner.IsNil() ? AString{} : Owner.ToShortString());
+ return 1;
+}
+
+
+
+
+
static int tolua_cMojangAPI_AddPlayerNameToUUIDMapping(lua_State * L)
{
cLuaState S(L);
if (
- !S.CheckParamUserTable(1, "cMojangAPI") ||
+ !S.CheckParamStaticSelf("cMojangAPI") ||
!S.CheckParamString(2) ||
- !S.CheckParamString(3) ||
+ !S.CheckParamUUID(3) ||
!S.CheckParamEnd(4)
)
{
@@ -2357,9 +2511,9 @@ static int tolua_cMojangAPI_AddPlayerNameToUUIDMapping(lua_State * L)
}
// Retrieve the parameters:
- AString UUID, PlayerName;
- S.GetStackValue(2, PlayerName);
- S.GetStackValue(3, UUID);
+ AString PlayerName;
+ cUUID UUID;
+ S.GetStackValues(2, PlayerName, UUID);
// Store in the cache:
cRoot::Get()->GetMojangAPI().AddPlayerNameToUUIDMapping(PlayerName, UUID);
@@ -2374,15 +2528,15 @@ static int tolua_cMojangAPI_GetPlayerNameFromUUID(lua_State * L)
{
cLuaState S(L);
if (
- !S.CheckParamUserTable(1, "cMojangAPI") ||
- !S.CheckParamString(2) ||
+ !S.CheckParamStaticSelf("cMojangAPI") ||
+ !S.CheckParamUUID(2) ||
!S.CheckParamEnd(4)
)
{
return 0;
}
- AString UUID;
+ cUUID UUID;
S.GetStackValue(2, UUID);
// If the UseOnlyCached param was given, read it; default to false
@@ -2407,7 +2561,7 @@ static int tolua_cMojangAPI_GetUUIDFromPlayerName(lua_State * L)
{
cLuaState S(L);
if (
- !S.CheckParamUserTable(1, "cMojangAPI") ||
+ !S.CheckParamStaticSelf("cMojangAPI") ||
!S.CheckParamString(2) ||
!S.CheckParamEnd(4)
)
@@ -2426,9 +2580,9 @@ static int tolua_cMojangAPI_GetUUIDFromPlayerName(lua_State * L)
lua_pop(L, 1);
}
- // Return the UUID:
- AString UUID = cRoot::Get()->GetMojangAPI().GetUUIDFromPlayerName(PlayerName, ShouldUseCacheOnly);
- S.Push(UUID);
+ // Return the UUID as a string:
+ cUUID UUID = cRoot::Get()->GetMojangAPI().GetUUIDFromPlayerName(PlayerName, ShouldUseCacheOnly);
+ S.Push(UUID.IsNil() ? AString{} : UUID.ToShortString());
return 1;
}
@@ -2440,7 +2594,7 @@ static int tolua_cMojangAPI_GetUUIDsFromPlayerNames(lua_State * L)
{
cLuaState S(L);
if (
- !S.CheckParamUserTable(1, "cMojangAPI") ||
+ !S.CheckParamStaticSelf("cMojangAPI") ||
!S.CheckParamTable(2) ||
!S.CheckParamEnd(4)
)
@@ -2476,23 +2630,23 @@ static int tolua_cMojangAPI_GetUUIDsFromPlayerNames(lua_State * L)
lua_newtable(L);
// Get the UUIDs:
- AStringVector UUIDs = cRoot::Get()->GetMojangAPI().GetUUIDsFromPlayerNames(PlayerNames, ShouldUseCacheOnly);
+ auto UUIDs = cRoot::Get()->GetMojangAPI().GetUUIDsFromPlayerNames(PlayerNames, ShouldUseCacheOnly);
if (UUIDs.size() != PlayerNames.size())
{
// A hard error has occured while processing the request, no UUIDs were returned. Return an empty table:
return 1;
}
- // Convert to output table, PlayerName -> UUID:
+ // Convert to output table, PlayerName -> UUID string:
size_t len = UUIDs.size();
for (size_t i = 0; i < len; i++)
{
- if (UUIDs[i].empty())
+ if (UUIDs[i].IsNil())
{
// No UUID was provided for PlayerName[i], skip it in the resulting table
continue;
}
- lua_pushlstring(L, UUIDs[i].c_str(), UUIDs[i].length());
+ S.Push(UUIDs[i].ToShortString());
lua_setfield(L, 3, PlayerNames[i].c_str());
}
return 1;
@@ -2504,13 +2658,13 @@ static int tolua_cMojangAPI_GetUUIDsFromPlayerNames(lua_State * L)
static int tolua_cMojangAPI_MakeUUIDDashed(lua_State * L)
{
- // Function signature: cMojangAPI:MakeUUIDDashed(UUID) -> string
+ // Function now non-existant but kept for API compatibility
// Check params:
cLuaState S(L);
if (
- !S.CheckParamUserTable(1, "cMojangAPI") ||
- !S.CheckParamString(2) ||
+ !S.CheckParamStaticSelf("cMojangAPI") ||
+ !S.CheckParamUUID(2) ||
!S.CheckParamEnd(3)
)
{
@@ -2518,11 +2672,11 @@ static int tolua_cMojangAPI_MakeUUIDDashed(lua_State * L)
}
// Get the params:
- AString UUID;
+ cUUID UUID;
S.GetStackValue(2, UUID);
// Push the result:
- S.Push(cRoot::Get()->GetMojangAPI().MakeUUIDDashed(UUID));
+ S.Push(UUID.ToLongString());
return 1;
}
@@ -2532,13 +2686,13 @@ static int tolua_cMojangAPI_MakeUUIDDashed(lua_State * L)
static int tolua_cMojangAPI_MakeUUIDShort(lua_State * L)
{
- // Function signature: cMojangAPI:MakeUUIDShort(UUID) -> string
+ // Function now non-existant but kept for API compatibility
// Check params:
cLuaState S(L);
if (
!S.CheckParamUserTable(1, "cMojangAPI") ||
- !S.CheckParamString(2) ||
+ !S.CheckParamUUID(2) ||
!S.CheckParamEnd(3)
)
{
@@ -2546,11 +2700,11 @@ static int tolua_cMojangAPI_MakeUUIDShort(lua_State * L)
}
// Get the params:
- AString UUID;
+ cUUID UUID;
S.GetStackValue(2, UUID);
// Push the result:
- S.Push(cRoot::Get()->GetMojangAPI().MakeUUIDShort(UUID));
+ S.Push(UUID.ToShortString());
return 1;
}
@@ -3053,6 +3207,66 @@ static int tolua_cLuaWindow_new_local(lua_State * tolua_S)
+static int tolua_cRoot_DoWithPlayerByUUID(lua_State * tolua_S)
+{
+ // Check params:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamSelf("cRoot") ||
+ !L.CheckParamUUID(2) ||
+ !L.CheckParamFunction(3) ||
+ !L.CheckParamEnd(4)
+ )
+ {
+ return 0;
+ }
+
+ class cCallback :
+ public cPlayerListCallback
+ {
+ public:
+ cCallback(cLuaState & a_LuaState) :
+ m_LuaState(a_LuaState)
+ {
+ }
+
+ virtual bool Item(cPlayer * a_Player) override
+ {
+ bool ret = false;
+ m_LuaState.Call(m_FnRef, a_Player, cLuaState::Return, ret);
+ return ret;
+ }
+
+ cLuaState & m_LuaState;
+ cLuaState::cRef m_FnRef;
+ } Callback(L);
+
+ // Get parameters:
+ cRoot * Self;
+ cUUID PlayerUUID;
+ L.GetStackValues(1, Self, PlayerUUID, Callback.m_FnRef);
+
+ if (PlayerUUID.IsNil())
+ {
+ return L.ApiParamError("Expected a non-nil UUID for parameter #1");
+ }
+ if (!Callback.m_FnRef.IsValid())
+ {
+ return L.ApiParamError("Expected a valid callback function for parameter #2");
+ }
+
+ // Call the function:
+ bool res = Self->DoWithPlayerByUUID(PlayerUUID, Callback);
+
+ // Push the result as the return value:
+ L.Push(res);
+ return 1;
+}
+
+
+
+
+
static int tolua_cRoot_GetBuildCommitID(lua_State * tolua_S)
{
cLuaState L(tolua_S);
@@ -3791,9 +4005,12 @@ void cManualBindings::Bind(lua_State * tolua_S)
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cClientHandle");
- tolua_constant(tolua_S, "MAX_VIEW_DISTANCE", cClientHandle::MAX_VIEW_DISTANCE);
- tolua_constant(tolua_S, "MIN_VIEW_DISTANCE", cClientHandle::MIN_VIEW_DISTANCE);
- tolua_function(tolua_S, "SendPluginMessage", tolua_cClientHandle_SendPluginMessage);
+ tolua_constant(tolua_S, "MAX_VIEW_DISTANCE", cClientHandle::MAX_VIEW_DISTANCE);
+ tolua_constant(tolua_S, "MIN_VIEW_DISTANCE", cClientHandle::MIN_VIEW_DISTANCE);
+ tolua_function(tolua_S, "SendPluginMessage", tolua_cClientHandle_SendPluginMessage);
+ tolua_function(tolua_S, "GetUUID", tolua_cClientHandle_GetUUID);
+ tolua_function(tolua_S, "GenerateOfflineUUID", tolua_cClientHandle_GenerateOfflineUUID);
+ tolua_function(tolua_S, "IsUUIDOnline", tolua_cClientHandle_IsUUIDOnline);
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cColor");
@@ -3881,6 +4098,11 @@ void cManualBindings::Bind(lua_State * tolua_S)
tolua_function(tolua_S, "DoWithMap", DoWithID<cMapManager, cMap, &cMapManager::DoWithMap>);
tolua_endmodule(tolua_S);
+ tolua_beginmodule(tolua_S, "cMobHeadEntity");
+ tolua_function(tolua_S, "SetOwner", tolua_cMobHeadEntity_SetOwner);
+ tolua_function(tolua_S, "GetOwnerUUID", tolua_cMobHeadEntity_GetOwnerUUID);
+ tolua_endmodule(tolua_S);
+
tolua_beginmodule(tolua_S, "cMojangAPI");
tolua_function(tolua_S, "AddPlayerNameToUUIDMapping", tolua_cMojangAPI_AddPlayerNameToUUIDMapping);
tolua_function(tolua_S, "GetPlayerNameFromUUID", tolua_cMojangAPI_GetPlayerNameFromUUID);
@@ -3894,6 +4116,7 @@ void cManualBindings::Bind(lua_State * tolua_S)
tolua_function(tolua_S, "GetPermissions", tolua_cPlayer_GetPermissions);
tolua_function(tolua_S, "GetRestrictions", tolua_cPlayer_GetRestrictions);
tolua_function(tolua_S, "PermissionMatches", tolua_cPlayer_PermissionMatches);
+ tolua_function(tolua_S, "GetUUID", tolua_cPlayer_GetUUID);
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cPlugin");
@@ -3923,8 +4146,8 @@ void cManualBindings::Bind(lua_State * tolua_S)
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cRoot");
+ tolua_function(tolua_S, "DoWithPlayerByUUID", tolua_cRoot_DoWithPlayerByUUID);
tolua_function(tolua_S, "FindAndDoWithPlayer", DoWith <cRoot, cPlayer, &cRoot::FindAndDoWithPlayer>);
- tolua_function(tolua_S, "DoWithPlayerByUUID", DoWith <cRoot, cPlayer, &cRoot::DoWithPlayerByUUID>);
tolua_function(tolua_S, "ForEachPlayer", ForEach<cRoot, cPlayer, &cRoot::ForEachPlayer>);
tolua_function(tolua_S, "ForEachWorld", ForEach<cRoot, cWorld, &cRoot::ForEachWorld>);
tolua_function(tolua_S, "GetBrewingRecipe", tolua_cRoot_GetBrewingRecipe);
diff --git a/src/Bindings/ManualBindings_RankManager.cpp b/src/Bindings/ManualBindings_RankManager.cpp
index 84ca67c4e..d24685d2b 100644
--- a/src/Bindings/ManualBindings_RankManager.cpp
+++ b/src/Bindings/ManualBindings_RankManager.cpp
@@ -8,6 +8,7 @@
#include "../Root.h"
#include "tolua++/include/tolua++.h"
#include "LuaState.h"
+#include "UUID.h"
@@ -266,7 +267,7 @@ static int tolua_cRankManager_GetAllPlayerUUIDs(lua_State * L)
cLuaState S(L);
if (
- !S.CheckParamUserTable(1, "cRankManager") ||
+ !S.CheckParamStaticSelf("cRankManager") ||
!S.CheckParamEnd(2)
)
{
@@ -274,10 +275,18 @@ static int tolua_cRankManager_GetAllPlayerUUIDs(lua_State * L)
}
// Get the player uuid's:
- AStringVector Players = cRoot::Get()->GetRankManager()->GetAllPlayerUUIDs();
+ std::vector<cUUID> Players = cRoot::Get()->GetRankManager()->GetAllPlayerUUIDs();
+
+ // Convert to string UUIDs
+ std::vector<AString> StrUUIDs;
+ StrUUIDs.reserve(Players.size());
+ for (const auto & UUID : Players)
+ {
+ StrUUIDs.push_back(UUID.ToShortString());
+ }
// Push the results:
- S.Push(Players);
+ S.Push(StrUUIDs);
return 1;
}
@@ -430,8 +439,8 @@ static int tolua_cRankManager_GetPlayerGroups(lua_State * L)
cLuaState S(L);
if (
- !S.CheckParamUserTable(1, "cRankManager") ||
- !S.CheckParamString(2) ||
+ !S.CheckParamStaticSelf("cRankManager") ||
+ !S.CheckParamUUID(2) ||
!S.CheckParamEnd(3)
)
{
@@ -439,7 +448,7 @@ static int tolua_cRankManager_GetPlayerGroups(lua_State * L)
}
// Get the params:
- AString PlayerUUID;
+ cUUID PlayerUUID;
S.GetStackValue(2, PlayerUUID);
// Get the groups:
@@ -462,8 +471,8 @@ static int tolua_cRankManager_GetPlayerMsgVisuals(lua_State * L)
cLuaState S(L);
if (
- !S.CheckParamUserTable(1, "cRankManager") ||
- !S.CheckParamString(2) ||
+ !S.CheckParamStaticSelf("cRankManager") ||
+ !S.CheckParamUUID(2) ||
!S.CheckParamEnd(3)
)
{
@@ -471,7 +480,7 @@ static int tolua_cRankManager_GetPlayerMsgVisuals(lua_State * L)
}
// Get the params:
- AString PlayerUUID;
+ cUUID PlayerUUID;
S.GetStackValue(2, PlayerUUID);
// Get the permissions:
@@ -498,8 +507,8 @@ static int tolua_cRankManager_GetPlayerPermissions(lua_State * L)
cLuaState S(L);
if (
- !S.CheckParamUserTable(1, "cRankManager") ||
- !S.CheckParamString(2) ||
+ !S.CheckParamStaticSelf("cRankManager") ||
+ !S.CheckParamUUID(2) ||
!S.CheckParamEnd(3)
)
{
@@ -507,7 +516,7 @@ static int tolua_cRankManager_GetPlayerPermissions(lua_State * L)
}
// Get the params:
- AString PlayerUUID;
+ cUUID PlayerUUID;
S.GetStackValue(2, PlayerUUID);
// Get the permissions:
@@ -530,8 +539,8 @@ static int tolua_cRankManager_GetPlayerRestrictions(lua_State * L)
cLuaState S(L);
if (
- !S.CheckParamUserTable(1, "cRankManager") ||
- !S.CheckParamString(2) ||
+ !S.CheckParamStaticSelf("cRankManager") ||
+ !S.CheckParamUUID(2) ||
!S.CheckParamEnd(3)
)
{
@@ -539,7 +548,7 @@ static int tolua_cRankManager_GetPlayerRestrictions(lua_State * L)
}
// Get the params:
- AString PlayerUUID;
+ cUUID PlayerUUID;
S.GetStackValue(2, PlayerUUID);
// Get the permissions:
@@ -562,8 +571,8 @@ static int tolua_cRankManager_GetPlayerRankName(lua_State * L)
cLuaState S(L);
if (
- !S.CheckParamUserTable(1, "cRankManager") ||
- !S.CheckParamString(2) ||
+ !S.CheckParamStaticSelf("cRankManager") ||
+ !S.CheckParamUUID(2) ||
!S.CheckParamEnd(3)
)
{
@@ -571,7 +580,7 @@ static int tolua_cRankManager_GetPlayerRankName(lua_State * L)
}
// Get the params:
- AString PlayerUUID;
+ cUUID PlayerUUID;
S.GetStackValue(2, PlayerUUID);
// Get the rank name:
@@ -594,8 +603,8 @@ static int tolua_cRankManager_GetPlayerName(lua_State * L)
cLuaState S(L);
if (
- !S.CheckParamUserTable(1, "cRankManager") ||
- !S.CheckParamString(2) ||
+ !S.CheckParamStaticSelf("cRankManager") ||
+ !S.CheckParamUUID(2) ||
!S.CheckParamEnd(3)
)
{
@@ -603,7 +612,7 @@ static int tolua_cRankManager_GetPlayerName(lua_State * L)
}
// Get the params:
- AString PlayerUUID;
+ cUUID PlayerUUID;
S.GetStackValue(2, PlayerUUID);
// Get the player name:
@@ -887,8 +896,8 @@ static int tolua_cRankManager_IsPlayerRankSet(lua_State * L)
cLuaState S(L);
if (
- !S.CheckParamUserTable(1, "cRankManager") ||
- !S.CheckParamString(2) ||
+ !S.CheckParamStaticSelf("cRankManager") ||
+ !S.CheckParamUUID(2) ||
!S.CheckParamEnd(3)
)
{
@@ -896,7 +905,7 @@ static int tolua_cRankManager_IsPlayerRankSet(lua_State * L)
}
// Get the params:
- AString PlayerUUID;
+ cUUID PlayerUUID;
S.GetStackValue(2, PlayerUUID);
// Get the response:
@@ -1067,8 +1076,8 @@ static int tolua_cRankManager_RemovePlayerRank(lua_State * L)
cLuaState S(L);
if (
- !S.CheckParamUserTable(1, "cRankManager") ||
- !S.CheckParamString(2) ||
+ !S.CheckParamStaticSelf("cRankManager") ||
+ !S.CheckParamUUID(2) ||
!S.CheckParamEnd(3)
)
{
@@ -1076,7 +1085,7 @@ static int tolua_cRankManager_RemovePlayerRank(lua_State * L)
}
// Get the params:
- AString PlayerUUID;
+ cUUID PlayerUUID;
S.GetStackValue(2, PlayerUUID);
// Remove the player's rank:
@@ -1219,8 +1228,9 @@ static int tolua_cRankManager_SetPlayerRank(lua_State * L)
cLuaState S(L);
if (
- !S.CheckParamUserTable(1, "cRankManager") ||
- !S.CheckParamString(2, 4) ||
+ !S.CheckParamStaticSelf("cRankManager") ||
+ !S.CheckParamUUID(2) ||
+ !S.CheckParamString(3, 4) ||
!S.CheckParamEnd(5)
)
{
@@ -1228,7 +1238,8 @@ static int tolua_cRankManager_SetPlayerRank(lua_State * L)
}
// Get the params:
- AString PlayerUUID, PlayerName, RankName;
+ AString PlayerName, RankName;
+ cUUID PlayerUUID;
S.GetStackValues(2, PlayerUUID, PlayerName, RankName);
// Set the rank:
diff --git a/src/Bindings/ManualBindings_World.cpp b/src/Bindings/ManualBindings_World.cpp
index 88e3917da..10b5daf1e 100644
--- a/src/Bindings/ManualBindings_World.cpp
+++ b/src/Bindings/ManualBindings_World.cpp
@@ -7,6 +7,7 @@
#include "tolua++/include/tolua++.h"
#include "../World.h"
#include "../Broadcaster.h"
+#include "../UUID.h"
#include "ManualBindings.h"
#include "LuaState.h"
#include "PluginLua.h"
@@ -206,6 +207,53 @@ static int tolua_cWorld_DoExplosionAt(lua_State * tolua_S)
+static int tolua_cWorld_DoWithPlayerByUUID(lua_State * tolua_S)
+{
+ // Check params:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamSelf("cWorld") ||
+ !L.CheckParamUUID(2) ||
+ !L.CheckParamFunction(3) ||
+ !L.CheckParamEnd(4)
+ )
+ {
+ return 0;
+ }
+
+ // Get parameters:
+ cWorld * Self;
+ cUUID PlayerUUID;
+ cLuaState::cRef FnRef;
+ L.GetStackValues(1, Self, PlayerUUID, FnRef);
+
+ if (PlayerUUID.IsNil())
+ {
+ return L.ApiParamError("Expected a non-nil UUID for parameter #1");
+ }
+ if (!FnRef.IsValid())
+ {
+ return L.ApiParamError("Expected a valid callback function for parameter #2");
+ }
+
+ // Call the function:
+ bool res = Self->DoWithPlayerByUUID(PlayerUUID, [&](cPlayer * a_Player)
+ {
+ bool ret = false;
+ L.Call(FnRef, a_Player, cLuaState::Return, ret);
+ return ret;
+ }
+ );
+
+ // Push the result as the return value:
+ L.Push(res);
+ return 1;
+}
+
+
+
+
+
static int tolua_cWorld_ForEachLoadedChunk(lua_State * tolua_S)
{
// Exported manually, because tolua doesn't support converting functions to functor types.
@@ -640,7 +688,7 @@ void cManualBindings::BindWorld(lua_State * tolua_S)
tolua_function(tolua_S, "DoWithMobHeadAt", DoWithXYZ<cWorld, cMobHeadEntity, &cWorld::DoWithMobHeadAt>);
tolua_function(tolua_S, "DoWithNoteBlockAt", DoWithXYZ<cWorld, cNoteEntity, &cWorld::DoWithNoteBlockAt>);
tolua_function(tolua_S, "DoWithPlayer", DoWith< cWorld, cPlayer, &cWorld::DoWithPlayer>);
- tolua_function(tolua_S, "DoWithPlayerByUUID", DoWith< cWorld, cPlayer, &cWorld::DoWithPlayerByUUID>);
+ tolua_function(tolua_S, "DoWithPlayerByUUID", tolua_cWorld_DoWithPlayerByUUID);
tolua_function(tolua_S, "FindAndDoWithPlayer", DoWith< cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>);
tolua_function(tolua_S, "ForEachBlockEntityInChunk", ForEachInChunk<cWorld, cBlockEntity, &cWorld::ForEachBlockEntityInChunk>);
tolua_function(tolua_S, "ForEachBrewingstandInChunk", ForEachInChunk<cWorld, cBrewingstandEntity, &cWorld::ForEachBrewingstandInChunk>);
diff --git a/src/BlockEntities/MobHeadEntity.cpp b/src/BlockEntities/MobHeadEntity.cpp
index 3bc7839b7..28e9febed 100644
--- a/src/BlockEntities/MobHeadEntity.cpp
+++ b/src/BlockEntities/MobHeadEntity.cpp
@@ -54,7 +54,8 @@ void cMobHeadEntity::SetType(const eMobHeadType & a_Type)
{
if ((!m_OwnerName.empty()) && (a_Type != SKULL_TYPE_PLAYER))
{
- m_OwnerName = m_OwnerUUID = m_OwnerTexture = m_OwnerTextureSignature = "";
+ m_OwnerName = m_OwnerTexture = m_OwnerTextureSignature = "";
+ m_OwnerUUID = cUUID{};
}
m_Type = a_Type;
m_World->BroadcastBlockEntity(m_PosX, m_PosY, m_PosZ);
@@ -102,7 +103,7 @@ void cMobHeadEntity::SetOwner(const cPlayer & a_Owner)
-void cMobHeadEntity::SetOwner(const AString & a_OwnerUUID, const AString & a_OwnerName, const AString & a_OwnerTexture, const AString & a_OwnerTextureSignature)
+void cMobHeadEntity::SetOwner(const cUUID & a_OwnerUUID, const AString & a_OwnerName, const AString & a_OwnerTexture, const AString & a_OwnerTextureSignature)
{
if (m_Type != SKULL_TYPE_PLAYER)
{
diff --git a/src/BlockEntities/MobHeadEntity.h b/src/BlockEntities/MobHeadEntity.h
index c8bfeb357..fe0ae71e4 100644
--- a/src/BlockEntities/MobHeadEntity.h
+++ b/src/BlockEntities/MobHeadEntity.h
@@ -10,6 +10,7 @@
#include "BlockEntity.h"
#include "Defines.h"
+#include "UUID.h"
@@ -42,9 +43,6 @@ public:
/** Set the player for mob heads with player type */
void SetOwner(const cPlayer & a_Owner);
- /** Sets the player components for the mob heads with player type. */
- void SetOwner(const AString & a_OwnerUUID, const AString & a_OwnerName, const AString & a_OwnerTexture, const AString & a_OwnerTextureSignature);
-
/** Returns the type of the mob head */
eMobHeadType GetType(void) const { return m_Type; }
@@ -54,9 +52,6 @@ public:
/** Returns the player name of the mob head */
AString GetOwnerName(void) const { return m_OwnerName; }
- /** Returns the player UUID of the mob head */
- AString GetOwnerUUID(void) const { return m_OwnerUUID; }
-
/** Returns the texture of the mob head */
AString GetOwnerTexture(void) const { return m_OwnerTexture; }
@@ -65,6 +60,15 @@ public:
// tolua_end
+ /** Sets the player components for the mob heads with player type. */
+ void SetOwner(
+ const cUUID & a_OwnerUUID, const AString & a_OwnerName,
+ const AString & a_OwnerTexture, const AString & a_OwnerTextureSignature
+ ); // Exported in ManualBindings.cpp
+
+ /** Returns the player UUID of the mob head */
+ cUUID GetOwnerUUID(void) const { return m_OwnerUUID; } // Exported in ManualBindings.cpp
+
// cBlockEntity overrides:
virtual void CopyFrom(const cBlockEntity & a_Src) override;
virtual bool UsedBy(cPlayer * a_Player) override;
@@ -76,7 +80,7 @@ private:
eMobHeadRotation m_Rotation;
AString m_OwnerName;
- AString m_OwnerUUID;
+ cUUID m_OwnerUUID;
AString m_OwnerTexture;
AString m_OwnerTextureSignature;
} ; // tolua_export
diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp
index 1a4dc8bb8..5b4cdb745 100644
--- a/src/ByteBuffer.cpp
+++ b/src/ByteBuffer.cpp
@@ -7,6 +7,7 @@
#include "ByteBuffer.h"
#include "Endianness.h"
+#include "UUID.h"
#include "OSSupport/IsThread.h"
@@ -32,16 +33,6 @@ Unfortunately it is very slow, so it is disabled even for regular DEBUG builds.
-static char ValueToHexDigit(UInt8 digit)
-{
- ASSERT(digit < 16);
- return "0123456789abcdef"[digit];
-}
-
-
-
-
-
#ifdef DEBUG_SINGLE_THREAD_ACCESS
/** Simple RAII class that is used for checking that no two threads are using an object simultanously.
@@ -506,22 +497,17 @@ bool cByteBuffer::ReadPosition64(int & a_BlockX, int & a_BlockY, int & a_BlockZ)
-bool cByteBuffer::ReadUUID(AString & a_Value)
+bool cByteBuffer::ReadUUID(cUUID & a_Value)
{
CHECK_THREAD
- if (!ReadString(a_Value, 16))
+ std::array<Byte, 16> UUIDBuf;
+ if (!ReadBuf(UUIDBuf.data(), UUIDBuf.size()))
{
return false;
}
- a_Value.resize(32);
- for (unsigned int i = 15; i < 16; i--)
- {
- a_Value[i * 2 + 1] = ValueToHexDigit(a_Value[i] & 0xf);
- a_Value[i * 2] = ValueToHexDigit(static_cast<UInt8>(a_Value[i]) >> 4);
- }
-
+ a_Value.FromRaw(UUIDBuf);
return true;
}
diff --git a/src/ByteBuffer.h b/src/ByteBuffer.h
index 761112721..e47f665a5 100644
--- a/src/ByteBuffer.h
+++ b/src/ByteBuffer.h
@@ -11,6 +11,8 @@
+// fwd:
+class cUUID;
/** An object that can store incoming bytes and lets its clients read the bytes sequentially
@@ -68,7 +70,7 @@ public:
bool ReadVarUTF8String (AString & a_Value); // string length as VarInt, then string as UTF-8
bool ReadLEInt (int & a_Value);
bool ReadPosition64 (int & a_BlockX, int & a_BlockY, int & a_BlockZ);
- bool ReadUUID (AString & a_Value); // UUID without dashes
+ bool ReadUUID (cUUID & a_Value);
/** Reads VarInt, assigns it to anything that can be assigned from an UInt64 (unsigned short, char, Byte, double, ...) */
template <typename T> bool ReadVarInt(T & a_Value)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3ae56e635..d7eb4e903 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -69,6 +69,7 @@ SET (SRCS
StringCompression.cpp
StringUtils.cpp
Tracer.cpp
+ UUID.cpp
VoronoiMap.cpp
WebAdmin.cpp
World.cpp
@@ -147,6 +148,7 @@ SET (HDRS
StringCompression.h
StringUtils.h
Tracer.h
+ UUID.h
Vector3.h
VoronoiMap.h
WebAdmin.h
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 5fc659fe1..caa2d8fd8 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -274,55 +274,28 @@ AString cClientHandle::FormatMessageType(bool ShouldAppendChatPrefixes, eMessage
-AString cClientHandle::GenerateOfflineUUID(const AString & a_Username)
+cUUID cClientHandle::GenerateOfflineUUID(const AString & a_Username)
{
// Online UUIDs are always version 4 (random)
// We use Version 3 (MD5 hash) UUIDs for the offline UUIDs
// This guarantees that they will never collide with an online UUID and can be distinguished.
- // 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
- // Note that we generate a short UUID (without the dashes)
// First make the username lowercase:
AString lcUsername = StrToLower(a_Username);
- // Generate an md5 checksum, and use it as base for the ID:
- unsigned char MD5[16];
- md5(reinterpret_cast<const unsigned char *>(lcUsername.c_str()), lcUsername.length(), MD5);
- MD5[6] &= 0x0f; // Need to trim to 4 bits only...
- MD5[8] &= 0x0f; // ... otherwise %01x overflows into two chars
- return Printf("%02x%02x%02x%02x%02x%02x3%01x%02x8%01x%02x%02x%02x%02x%02x%02x%02x",
- MD5[0], MD5[1], MD5[2], MD5[3],
- MD5[4], MD5[5], MD5[6], MD5[7],
- MD5[8], MD5[9], MD5[10], MD5[11],
- MD5[12], MD5[13], MD5[14], MD5[15]
- );
+ return cUUID::GenerateVersion3(lcUsername);
}
-bool cClientHandle::IsUUIDOnline(const AString & a_UUID)
+bool cClientHandle::IsUUIDOnline(const cUUID & a_UUID)
{
// Online UUIDs are always version 4 (random)
// We use Version 3 (MD5 hash) UUIDs for the offline UUIDs
// This guarantees that they will never collide with an online UUID and can be distinguished.
- // The version-specifying char is at pos #12 of raw UUID, pos #14 in dashed-UUID.
- switch (a_UUID.size())
- {
- case 32:
- {
- // This is the UUID format without dashes, the version char is at pos #12:
- return (a_UUID[12] == '4');
- }
- case 36:
- {
- // This is the UUID format with dashes, the version char is at pos #14:
- return (a_UUID[14] == '4');
- }
- }
- return false;
+ return (a_UUID.Version() == 4);
}
@@ -342,7 +315,7 @@ void cClientHandle::Kick(const AString & a_Reason)
-void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID, const Json::Value & a_Properties)
+void cClientHandle::Authenticate(const AString & a_Name, const cUUID & a_UUID, const Json::Value & a_Properties)
{
// Atomically increment player count (in server thread)
cRoot::Get()->GetServer()->PlayerCreated();
@@ -366,7 +339,7 @@ void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID,
m_Username = a_Name;
// Only assign UUID and properties if not already pre-assigned (BungeeCord sends those in the Handshake packet):
- if (m_UUID.empty())
+ if (m_UUID.IsNil())
{
m_UUID = a_UUID;
}
@@ -1661,7 +1634,7 @@ void cClientHandle::HandleSlotSelected(Int16 a_SlotNum)
-void cClientHandle::HandleSpectate(const AString & a_PlayerUUID)
+void cClientHandle::HandleSpectate(const cUUID & a_PlayerUUID)
{
m_Player->GetWorld()->DoWithPlayerByUUID(a_PlayerUUID, [=](cPlayer * a_ToSpectate)
{
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index 2a661e283..09188f2ae 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -16,6 +16,7 @@
#include "json/json.h"
#include "ChunkSender.h"
#include "EffectID.h"
+#include "UUID.h"
@@ -72,13 +73,13 @@ public: // tolua_export
cPlayer * GetPlayer(void) { return m_Player; } // tolua_export
- /** Returns the player's UUID, as used by the protocol, in the short form (no dashes) */
- const AString & GetUUID(void) const { return m_UUID; } // tolua_export
+ /** Returns the player's UUID, as used by the protocol */
+ const cUUID & GetUUID(void) const { return m_UUID; } // Exported in ManualBindings.cpp
- /** Sets the player's UUID, as used by the protocol. Short UUID form (no dashes) is expected.
+ /** Sets the player's UUID, as used by the protocol.
Used mainly by BungeeCord compatibility code - when authenticating is done on the BungeeCord server
and the results are passed to MCS running in offline mode. */
- void SetUUID(const AString & a_UUID) { ASSERT(a_UUID.size() == 32); m_UUID = a_UUID; }
+ void SetUUID(const cUUID & a_UUID) { ASSERT(!a_UUID.IsNil()); m_UUID = a_UUID; }
const Json::Value & GetProperties(void) const { return m_Properties; }
@@ -95,15 +96,12 @@ public: // tolua_export
/** 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.
- Returns a 32-char UUID (no dashes). */
- static AString GenerateOfflineUUID(const AString & a_Username); // tolua_export
+ Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same. */
+ static cUUID GenerateOfflineUUID(const AString & a_Username); // Exported in ManualBindings.cpp
/** Returns true if the UUID is generated by online auth, false if it is an offline-generated UUID.
- We use Version-3 UUIDs for offline UUIDs, online UUIDs are Version-4, thus we can tell them apart.
- Accepts both 32-char and 36-char UUIDs (with and without dashes).
- If the string given is not a valid UUID, returns false. */
- static bool IsUUIDOnline(const AString & a_UUID); // tolua_export
+ We use Version-3 UUIDs for offline UUIDs, online UUIDs are Version-4, thus we can tell them apart. */
+ static bool IsUUIDOnline(const cUUID & a_UUID); // Exported in ManualBindings.cpp
/** Formats the type of message with the proper color and prefix for sending to the client. */
static AString FormatMessageType(bool ShouldAppendChatPrefixes, eMessageType a_ChatPrefix, const AString & a_AdditionalData);
@@ -113,7 +111,7 @@ public: // tolua_export
void Kick(const AString & a_Reason); // tolua_export
/** Authenticates the specified user, called by cAuthenticator */
- void Authenticate(const AString & a_Name, const AString & a_UUID, const Json::Value & a_Properties);
+ void Authenticate(const AString & a_Name, const cUUID & a_UUID, const Json::Value & a_Properties);
/** This function sends a new unloaded chunk to the player. Returns true if all chunks are loaded. */
bool StreamNextChunk();
@@ -336,7 +334,7 @@ public: // tolua_export
void HandleRespawn (void);
void HandleRightClick (int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, const cItem & a_HeldItem);
void HandleSlotSelected (Int16 a_SlotNum);
- void HandleSpectate (const AString & a_PlayerUUID);
+ void HandleSpectate (const cUUID & a_PlayerUUID);
void HandleSteerVehicle (float Forward, float Sideways);
void HandleTabCompletion (const AString & a_Text);
void HandleUpdateSign (
@@ -498,8 +496,8 @@ private:
/** ID used for identification during authenticating. Assigned sequentially for each new instance. */
int m_UniqueID;
- /** Contains the UUID used by Mojang to identify the player's account. Short UUID stored here (without dashes) */
- AString m_UUID;
+ /** Contains the UUID used by Mojang to identify the player's account. */
+ cUUID m_UUID;
/** Set to true when the chunk where the player is is sent to the client. Used for spawning the player */
bool m_HasSentPlayerChunk;
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 60da8c758..fb2274cad 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -84,7 +84,7 @@ cPlayer::cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName) :
m_bIsInBed(false),
m_TicksUntilNextSave(PLAYER_INVENTORY_SAVE_INTERVAL),
m_bIsTeleporting(false),
- m_UUID((a_Client != nullptr) ? a_Client->GetUUID() : ""),
+ m_UUID((a_Client != nullptr) ? a_Client->GetUUID() : cUUID{}),
m_CustomName(""),
m_SkinParts(0),
m_MainHand(mhRight)
@@ -2077,7 +2077,7 @@ bool cPlayer::LoadFromDisk(cWorldPtr & a_World)
}
// Load from the offline UUID file, if allowed:
- AString OfflineUUID = cClientHandle::GenerateOfflineUUID(GetName());
+ cUUID OfflineUUID = cClientHandle::GenerateOfflineUUID(GetName());
const char * OfflineUsage = " (unused)";
if (cRoot::Get()->GetServer()->ShouldLoadOfflinePlayerData())
{
@@ -2105,7 +2105,7 @@ bool cPlayer::LoadFromDisk(cWorldPtr & a_World)
// None of the files loaded successfully
LOG("Player data file not found for %s (%s, offline %s%s), will be reset to defaults.",
- GetName().c_str(), m_UUID.c_str(), OfflineUUID.c_str(), OfflineUsage
+ GetName().c_str(), m_UUID.ToShortString().c_str(), OfflineUUID.ToShortString().c_str(), OfflineUsage
);
if (a_World == nullptr)
@@ -2220,7 +2220,7 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World)
bool cPlayer::SaveToDisk()
{
cFile::CreateFolder(FILE_IO_PREFIX + AString("players/")); // Create the "players" folder, if it doesn't exist yet (#1268)
- cFile::CreateFolder(FILE_IO_PREFIX + AString("players/") + m_UUID.substr(0, 2));
+ cFile::CreateFolder(FILE_IO_PREFIX + AString("players/") + m_UUID.ToShortString().substr(0, 2));
// create the JSON data
Json::Value JSON_PlayerPosition;
@@ -2879,10 +2879,9 @@ void cPlayer::RemoveClientHandle(void)
-AString cPlayer::GetUUIDFileName(const AString & a_UUID)
+AString cPlayer::GetUUIDFileName(const cUUID & a_UUID)
{
- AString UUID = cMojangAPI::MakeUUIDDashed(a_UUID);
- ASSERT(UUID.length() == 36);
+ AString UUID = a_UUID.ToLongString();
AString res("players/");
res.append(UUID, 0, 2);
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index 5b0aa84a8..5c08151c8 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -8,6 +8,8 @@
#include "../Statistics.h"
+#include "../UUID.h"
+
@@ -488,14 +490,14 @@ public:
/** Whether placing the given blocks would intersect any entitiy */
bool DoesPlacingBlocksIntersectEntity(const sSetBlockVector & a_Blocks);
+ /** Returns the UUID that has been read from the client, or nil if not available. */
+ const cUUID & GetUUID(void) const { return m_UUID; } // Exported in ManualBindings.cpp
+
// tolua_begin
/** Returns wheter the player can fly or not. */
virtual bool CanFly(void) const { return m_CanFly; }
- /** Returns the UUID (short format) that has been read from the client, or empty string if not available. */
- const AString & GetUUID(void) const { return m_UUID; }
-
/** (Re)loads the rank and permissions from the cRankManager.
Expects the m_UUID member to be valid.
Loads the m_Rank, m_Permissions, m_MsgPrefix, m_MsgSuffix and m_MsgNameColorCode members. */
@@ -694,9 +696,9 @@ protected:
*/
bool m_bIsTeleporting;
- /** The short UUID (no dashes) of the player, as read from the ClientHandle.
- If no ClientHandle is given, the UUID is initialized to empty. */
- AString m_UUID;
+ /** The UUID of the player, as read from the ClientHandle.
+ If no ClientHandle is given, the UUID is nil. */
+ cUUID m_UUID;
AString m_CustomName;
@@ -731,7 +733,7 @@ protected:
/** Returns the filename for the player data based on the UUID given.
This can be used both for online and offline UUIDs. */
- AString GetUUIDFileName(const AString & a_UUID);
+ AString GetUUIDFileName(const cUUID & a_UUID);
private:
diff --git a/src/Mobs/Ocelot.h b/src/Mobs/Ocelot.h
index 59b4f25af..75758a973 100644
--- a/src/Mobs/Ocelot.h
+++ b/src/Mobs/Ocelot.h
@@ -2,6 +2,7 @@
#pragma once
#include "PassiveMonster.h"
+#include "../UUID.h"
@@ -40,14 +41,14 @@ public:
bool IsTame (void) const override { return m_IsTame; }
bool IsBegging (void) const { return m_IsBegging; }
AString GetOwnerName (void) const { return m_OwnerName; }
- AString GetOwnerUUID (void) const { return m_OwnerUUID; }
+ cUUID GetOwnerUUID (void) const { return m_OwnerUUID; }
eCatType GetOcelotType (void) const { return m_CatType; }
// Set functions
void SetIsSitting (bool a_IsSitting) { m_IsSitting = a_IsSitting; }
void SetIsTame (bool a_IsTame) { m_IsTame = a_IsTame; }
void SetIsBegging (bool a_IsBegging) { m_IsBegging = a_IsBegging; }
- void SetOwner (const AString & a_NewOwnerName, const AString & a_NewOwnerUUID)
+ void SetOwner (const AString & a_NewOwnerName, const cUUID & a_NewOwnerUUID)
{
m_OwnerName = a_NewOwnerName;
m_OwnerUUID = a_NewOwnerUUID;
@@ -66,7 +67,7 @@ protected:
/** Only check for a nearby player holding the breeding items every 23 ticks. */
int m_CheckPlayerTickCount;
AString m_OwnerName;
- AString m_OwnerUUID;
+ cUUID m_OwnerUUID;
} ;
diff --git a/src/Mobs/Wolf.cpp b/src/Mobs/Wolf.cpp
index 33a9b31ee..f3b859c76 100644
--- a/src/Mobs/Wolf.cpp
+++ b/src/Mobs/Wolf.cpp
@@ -117,7 +117,7 @@ bool cWolf::Attack(std::chrono::milliseconds a_Dt)
-void cWolf::ReceiveNearbyFightInfo(AString a_PlayerID, cPawn * a_Opponent, bool a_IsPlayerInvolved)
+void cWolf::ReceiveNearbyFightInfo(const cUUID & a_PlayerID, cPawn * a_Opponent, bool a_IsPlayerInvolved)
{
if (
(a_Opponent == nullptr) || IsSitting() || (!IsTame()) ||
diff --git a/src/Mobs/Wolf.h b/src/Mobs/Wolf.h
index e05fedbf8..861419ba8 100644
--- a/src/Mobs/Wolf.h
+++ b/src/Mobs/Wolf.h
@@ -2,6 +2,7 @@
#pragma once
#include "PassiveAggressiveMonster.h"
+#include "../UUID.h"
class cEntity;
@@ -31,7 +32,7 @@ public:
bool IsBegging (void) const { return m_IsBegging; }
bool IsAngry (void) const { return m_IsAngry; }
AString GetOwnerName (void) const { return m_OwnerName; }
- AString GetOwnerUUID (void) const { return m_OwnerUUID; }
+ cUUID GetOwnerUUID (void) const { return m_OwnerUUID; }
int GetCollarColor(void) const { return m_CollarColor; }
// Set functions
@@ -40,7 +41,7 @@ public:
void SetIsBegging (bool a_IsBegging) { m_IsBegging = a_IsBegging; }
void SetIsAngry (bool a_IsAngry) { m_IsAngry = a_IsAngry; }
void SetCollarColor(int a_CollarColor) { m_CollarColor = a_CollarColor; }
- void SetOwner (const AString & a_NewOwnerName, const AString & a_NewOwnerUUID)
+ void SetOwner (const AString & a_NewOwnerName, const cUUID & a_NewOwnerUUID)
{
m_OwnerName = a_NewOwnerName;
m_OwnerUUID = a_NewOwnerUUID;
@@ -48,12 +49,12 @@ public:
/** Notfies the wolf of a nearby fight.
The wolf may then decide to attack a_Opponent.
- If a_IsPlayer is true, then the player whose ID is a_PlayerID is fighting a_Opponent
- If false, then a wolf owned by the player whose ID is a_PlayerID is fighting a_Opponent
- @param a_PlayerID The ID of the fighting player, or the ID of the owner whose wolf is fighting.
+ If a_IsPlayerInvolved is true, then the player whose UUID is a_PlayerUUID is fighting a_Opponent
+ If false, then a wolf owned by the player whose UUID is a_PlayerUUID is fighting a_Opponent
+ @param a_PlayerUUID The UUID of the fighting player, or the UUID of the owner whose wolf is fighting.
@param a_Opponent The opponent who is being faught.
@param a_IsPlayerInvolved Whether the fighter a player or a wolf. */
- void ReceiveNearbyFightInfo(AString a_PlayerID, cPawn * a_Opponent, bool a_IsPlayerInvolved);
+ void ReceiveNearbyFightInfo(const cUUID & a_PlayerUUID, cPawn * a_Opponent, bool a_IsPlayerInvolved);
virtual void InStateIdle(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
@@ -64,7 +65,7 @@ protected:
bool m_IsBegging;
bool m_IsAngry;
AString m_OwnerName;
- AString m_OwnerUUID;
+ cUUID m_OwnerUUID;
int m_CollarColor;
int m_NotificationCooldown;
} ;
diff --git a/src/Protocol/Authenticator.cpp b/src/Protocol/Authenticator.cpp
index 12e963143..d46127d34 100644
--- a/src/Protocol/Authenticator.cpp
+++ b/src/Protocol/Authenticator.cpp
@@ -6,6 +6,7 @@
#include "../Root.h"
#include "../Server.h"
#include "../ClientHandle.h"
+#include "../UUID.h"
#include "../IniFile.h"
#include "json/json.h"
@@ -119,11 +120,11 @@ void cAuthenticator::Execute(void)
Lock.Unlock();
AString NewUserName = UserName;
- AString UUID;
+ cUUID UUID;
Json::Value Properties;
if (AuthWithYggdrasil(NewUserName, ServerID, UUID, Properties))
{
- LOGINFO("User %s authenticated with UUID %s", NewUserName.c_str(), UUID.c_str());
+ LOGINFO("User %s authenticated with UUID %s", NewUserName.c_str(), UUID.ToShortString().c_str());
cRoot::Get()->AuthenticateUser(ClientID, NewUserName, UUID, Properties);
}
else
@@ -137,7 +138,7 @@ void cAuthenticator::Execute(void)
-bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_ServerId, AString & a_UUID, Json::Value & a_Properties)
+bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_ServerId, cUUID & a_UUID, Json::Value & a_Properties)
{
LOGD("Trying to authenticate user %s", a_UserName.c_str());
@@ -192,8 +193,12 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S
return false;
}
a_UserName = root.get("name", "Unknown").asString();
- a_UUID = cMojangAPI::MakeUUIDShort(root.get("id", "").asString());
a_Properties = root["properties"];
+ if (!a_UUID.FromString(root.get("id", "").asString()))
+ {
+ LOGWARNING("cAuthenticator: Recieved invalid UUID format");
+ return false;
+ }
// Store the player's profile in the MojangAPI caches:
cRoot::Get()->GetMojangAPI().AddPlayerProfile(a_UserName, a_UUID, a_Properties);
diff --git a/src/Protocol/Authenticator.h b/src/Protocol/Authenticator.h
index 5ce06093c..98bf17512 100644
--- a/src/Protocol/Authenticator.h
+++ b/src/Protocol/Authenticator.h
@@ -14,12 +14,10 @@
#include "../OSSupport/IsThread.h"
+// fwd:
+class cUUID;
class cSettingsRepositoryInterface;
-
-
-
-
namespace Json
{
class Value;
@@ -90,7 +88,7 @@ private:
/** Returns true if the user authenticated okay, false on error
Returns the case-corrected username, UUID, and properties (eg. skin). */
- bool AuthWithYggdrasil(AString & a_UserName, const AString & a_ServerId, AString & a_UUID, Json::Value & a_Properties);
+ bool AuthWithYggdrasil(AString & a_UserName, const AString & a_ServerId, cUUID & a_UUID, Json::Value & a_Properties);
};
diff --git a/src/Protocol/MojangAPI.cpp b/src/Protocol/MojangAPI.cpp
index 4d5361479..5a11356c1 100644
--- a/src/Protocol/MojangAPI.cpp
+++ b/src/Protocol/MojangAPI.cpp
@@ -154,7 +154,7 @@ static const AString & GetCACerts(void)
cMojangAPI::sProfile::sProfile(
const AString & a_PlayerName,
- const AString & a_UUID,
+ const cUUID & a_UUID,
const Json::Value & a_Properties,
Int64 a_DateTime
) :
@@ -291,7 +291,7 @@ void cMojangAPI::Start(cSettingsRepositoryInterface & a_Settings, bool a_ShouldA
-AString cMojangAPI::GetUUIDFromPlayerName(const AString & a_PlayerName, bool a_UseOnlyCached)
+cUUID cMojangAPI::GetUUIDFromPlayerName(const AString & a_PlayerName, bool a_UseOnlyCached)
{
// Convert the playername to lowercase:
AString lcPlayerName = StrToLower(a_PlayerName);
@@ -299,8 +299,7 @@ AString cMojangAPI::GetUUIDFromPlayerName(const AString & a_PlayerName, bool a_U
// Request the cache to query the name if not yet cached:
if (!a_UseOnlyCached)
{
- AStringVector PlayerNames;
- PlayerNames.push_back(lcPlayerName);
+ AStringVector PlayerNames{ lcPlayerName };
CacheNamesToUUIDs(PlayerNames);
}
@@ -310,7 +309,7 @@ AString cMojangAPI::GetUUIDFromPlayerName(const AString & a_PlayerName, bool a_U
if (itr == m_NameToUUID.end())
{
// No UUID found
- return "";
+ return {};
}
return itr->second.m_UUID;
}
@@ -319,15 +318,12 @@ AString cMojangAPI::GetUUIDFromPlayerName(const AString & a_PlayerName, bool a_U
-AString cMojangAPI::GetPlayerNameFromUUID(const AString & a_UUID, bool a_UseOnlyCached)
+AString cMojangAPI::GetPlayerNameFromUUID(const cUUID & a_UUID, bool a_UseOnlyCached)
{
- // Normalize the UUID to lowercase short format that is used as the map key:
- AString UUID = MakeUUIDShort(a_UUID);
-
// Retrieve from caches:
{
cCSLock Lock(m_CSUUIDToProfile);
- cProfileMap::const_iterator itr = m_UUIDToProfile.find(UUID);
+ auto itr = m_UUIDToProfile.find(a_UUID);
if (itr != m_UUIDToProfile.end())
{
return itr->second.m_PlayerName;
@@ -335,7 +331,7 @@ AString cMojangAPI::GetPlayerNameFromUUID(const AString & a_UUID, bool a_UseOnly
}
{
cCSLock Lock(m_CSUUIDToName);
- cProfileMap::const_iterator itr = m_UUIDToName.find(UUID);
+ auto itr = m_UUIDToName.find(a_UUID);
if (itr != m_UUIDToName.end())
{
return itr->second.m_PlayerName;
@@ -345,19 +341,19 @@ AString cMojangAPI::GetPlayerNameFromUUID(const AString & a_UUID, bool a_UseOnly
// Name not yet cached, request cache and retry:
if (!a_UseOnlyCached)
{
- CacheUUIDToProfile(UUID);
+ CacheUUIDToProfile(a_UUID);
return GetPlayerNameFromUUID(a_UUID, true);
}
// No value found, none queried. Return an error:
- return "";
+ return {};
}
-AStringVector cMojangAPI::GetUUIDsFromPlayerNames(const AStringVector & a_PlayerNames, bool a_UseOnlyCached)
+std::vector<cUUID> cMojangAPI::GetUUIDsFromPlayerNames(const AStringVector & a_PlayerNames, bool a_UseOnlyCached)
{
// Convert all playernames to lowercase:
AStringVector PlayerNames;
@@ -374,7 +370,7 @@ AStringVector cMojangAPI::GetUUIDsFromPlayerNames(const AStringVector & a_Player
// Retrieve from cache:
size_t idx = 0;
- AStringVector res;
+ std::vector<cUUID> res;
res.resize(PlayerNames.size());
cCSLock Lock(m_CSNameToUUID);
for (AStringVector::const_iterator itr = PlayerNames.begin(), end = PlayerNames.end(); itr != end; ++itr, ++idx)
@@ -392,17 +388,16 @@ AStringVector cMojangAPI::GetUUIDsFromPlayerNames(const AStringVector & a_Player
-void cMojangAPI::AddPlayerNameToUUIDMapping(const AString & a_PlayerName, const AString & a_UUID)
+void cMojangAPI::AddPlayerNameToUUIDMapping(const AString & a_PlayerName, const cUUID & a_UUID)
{
- AString UUID = MakeUUIDShort(a_UUID);
Int64 Now = time(nullptr);
{
cCSLock Lock(m_CSNameToUUID);
- m_NameToUUID[StrToLower(a_PlayerName)] = sProfile(a_PlayerName, UUID, "", "", Now);
+ m_NameToUUID[StrToLower(a_PlayerName)] = sProfile(a_PlayerName, a_UUID, "", "", Now);
}
{
cCSLock Lock(m_CSUUIDToName);
- m_UUIDToName[UUID] = sProfile(a_PlayerName, UUID, "", "", Now);
+ m_UUIDToName[a_UUID] = sProfile(a_PlayerName, a_UUID, "", "", Now);
}
NotifyNameUUID(a_PlayerName, a_UUID);
}
@@ -411,21 +406,20 @@ void cMojangAPI::AddPlayerNameToUUIDMapping(const AString & a_PlayerName, const
-void cMojangAPI::AddPlayerProfile(const AString & a_PlayerName, const AString & a_UUID, const Json::Value & a_Properties)
+void cMojangAPI::AddPlayerProfile(const AString & a_PlayerName, const cUUID & a_UUID, const Json::Value & a_Properties)
{
- AString UUID = MakeUUIDShort(a_UUID);
Int64 Now = time(nullptr);
{
cCSLock Lock(m_CSNameToUUID);
- m_NameToUUID[StrToLower(a_PlayerName)] = sProfile(a_PlayerName, UUID, "", "", Now);
+ m_NameToUUID[StrToLower(a_PlayerName)] = sProfile(a_PlayerName, a_UUID, "", "", Now);
}
{
cCSLock Lock(m_CSUUIDToName);
- m_UUIDToName[UUID] = sProfile(a_PlayerName, UUID, "", "", Now);
+ m_UUIDToName[a_UUID] = sProfile(a_PlayerName, a_UUID, "", "", Now);
}
{
cCSLock Lock(m_CSUUIDToProfile);
- m_UUIDToProfile[UUID] = sProfile(a_PlayerName, UUID, a_Properties, Now);
+ m_UUIDToProfile[a_UUID] = sProfile(a_PlayerName, a_UUID, a_Properties, Now);
}
NotifyNameUUID(a_PlayerName, a_UUID);
}
@@ -488,74 +482,6 @@ bool cMojangAPI::SecureRequest(const AString & a_ServerName, const AString & a_R
-AString cMojangAPI::MakeUUIDShort(const AString & a_UUID)
-{
- // Note: we only check the string's length, not the actual content
- switch (a_UUID.size())
- {
- case 32:
- {
- // Already is a short UUID, only lowercase
- return StrToLower(a_UUID);
- }
-
- case 36:
- {
- // Remove the dashes from the string by appending together the parts between them:
- AString res;
- res.reserve(32);
- res.append(a_UUID, 0, 8);
- res.append(a_UUID, 9, 4);
- res.append(a_UUID, 14, 4);
- res.append(a_UUID, 19, 4);
- res.append(a_UUID, 24, 12);
- return StrToLower(res);
- }
- }
- LOGWARNING("%s: Not an UUID: \"%s\".", __FUNCTION__, a_UUID.c_str());
- return "";
-}
-
-
-
-
-
-AString cMojangAPI::MakeUUIDDashed(const AString & a_UUID)
-{
- // Note: we only check the string's length, not the actual content
- switch (a_UUID.size())
- {
- case 36:
- {
- // Already is a dashed UUID, only lowercase
- return StrToLower(a_UUID);
- }
-
- case 32:
- {
- // Insert dashes at the proper positions:
- AString res;
- res.reserve(36);
- res.append(a_UUID, 0, 8);
- res.push_back('-');
- res.append(a_UUID, 8, 4);
- res.push_back('-');
- res.append(a_UUID, 12, 4);
- res.push_back('-');
- res.append(a_UUID, 16, 4);
- res.push_back('-');
- res.append(a_UUID, 20, 12);
- return StrToLower(res);
- }
- }
- LOGWARNING("%s: Not an UUID: \"%s\".", __FUNCTION__, a_UUID.c_str());
- return "";
-}
-
-
-
-
-
void cMojangAPI::LoadCachesFromDisk(void)
{
try
@@ -571,9 +497,15 @@ void cMojangAPI::LoadCachesFromDisk(void)
while (stmt.executeStep())
{
AString PlayerName = stmt.getColumn(0);
- AString UUID = stmt.getColumn(1);
+ AString StringUUID = stmt.getColumn(1);
Int64 DateTime = stmt.getColumn(2);
- UUID = MakeUUIDShort(UUID);
+
+ cUUID UUID;
+ if (!UUID.FromString(StringUUID))
+ {
+ continue; // Invalid UUID
+ }
+
m_NameToUUID[StrToLower(PlayerName)] = sProfile(PlayerName, UUID, "", "", DateTime);
m_UUIDToName[UUID] = sProfile(PlayerName, UUID, "", "", DateTime);
}
@@ -583,11 +515,17 @@ void cMojangAPI::LoadCachesFromDisk(void)
while (stmt.executeStep())
{
AString PlayerName = stmt.getColumn(0);
- AString UUID = stmt.getColumn(1);
+ AString StringUUID = stmt.getColumn(1);
AString Textures = stmt.getColumn(2);
AString TexturesSignature = stmt.getColumn(2);
Int64 DateTime = stmt.getColumn(4);
- UUID = MakeUUIDShort(UUID);
+
+ cUUID UUID;
+ if (!UUID.FromString(StringUUID))
+ {
+ continue; // Invalid UUID
+ }
+
m_UUIDToProfile[UUID] = sProfile(PlayerName, UUID, Textures, TexturesSignature, DateTime);
}
}
@@ -620,16 +558,17 @@ void cMojangAPI::SaveCachesToDisk(void)
{
SQLite::Statement stmt(db, "INSERT INTO PlayerNameToUUID(PlayerName, UUID, DateTime) VALUES (?, ?, ?)");
cCSLock Lock(m_CSNameToUUID);
- for (cProfileMap::const_iterator itr = m_NameToUUID.begin(), end = m_NameToUUID.end(); itr != end; ++itr)
+ for (auto & NameToUUID : m_NameToUUID)
{
- if (itr->second.m_DateTime < LimitDateTime)
+ auto & Profile = NameToUUID.second;
+ if (Profile.m_DateTime < LimitDateTime)
{
// This item is too old, do not save
continue;
}
- stmt.bind(1, itr->second.m_PlayerName);
- stmt.bind(2, itr->second.m_UUID);
- stmt.bind(3, itr->second.m_DateTime);
+ stmt.bind(1, Profile.m_PlayerName);
+ stmt.bind(2, Profile.m_UUID.ToShortString());
+ stmt.bind(3, Profile.m_DateTime);
stmt.exec();
stmt.reset();
}
@@ -639,18 +578,19 @@ void cMojangAPI::SaveCachesToDisk(void)
{
SQLite::Statement stmt(db, "INSERT INTO UUIDToProfile(UUID, PlayerName, Textures, TexturesSignature, DateTime) VALUES (?, ?, ?, ?, ?)");
cCSLock Lock(m_CSUUIDToProfile);
- for (cProfileMap::const_iterator itr = m_UUIDToProfile.begin(), end = m_UUIDToProfile.end(); itr != end; ++itr)
+ for (auto & UUIDToProfile : m_UUIDToProfile)
{
- if (itr->second.m_DateTime < LimitDateTime)
+ auto & Profile = UUIDToProfile.second;
+ if (Profile.m_DateTime < LimitDateTime)
{
// This item is too old, do not save
continue;
}
- stmt.bind(1, itr->second.m_UUID);
- stmt.bind(2, itr->second.m_PlayerName);
- stmt.bind(3, itr->second.m_Textures);
- stmt.bind(4, itr->second.m_TexturesSignature);
- stmt.bind(5, itr->second.m_DateTime);
+ stmt.bind(1, Profile.m_UUID.ToShortString());
+ stmt.bind(2, Profile.m_PlayerName);
+ stmt.bind(3, Profile.m_Textures);
+ stmt.bind(4, Profile.m_TexturesSignature);
+ stmt.bind(5, Profile.m_DateTime);
stmt.exec();
stmt.reset();
}
@@ -762,8 +702,8 @@ void cMojangAPI::QueryNamesToUUIDs(AStringVector & a_NamesToQuery)
{
Json::Value & Val = root[idx];
AString JsonName = Val.get("name", "").asString();
- AString JsonUUID = MakeUUIDShort(Val.get("id", "").asString());
- if (JsonUUID.empty())
+ cUUID JsonUUID;
+ if (!JsonUUID.FromString(Val.get("id", "").asString()))
{
continue;
}
@@ -779,8 +719,8 @@ void cMojangAPI::QueryNamesToUUIDs(AStringVector & a_NamesToQuery)
{
Json::Value & Val = root[idx];
AString JsonName = Val.get("name", "").asString();
- AString JsonUUID = MakeUUIDShort(Val.get("id", "").asString());
- if (JsonUUID.empty())
+ cUUID JsonUUID;
+ if (!JsonUUID.FromString(Val.get("id", "").asString()))
{
continue;
}
@@ -794,10 +734,8 @@ void cMojangAPI::QueryNamesToUUIDs(AStringVector & a_NamesToQuery)
-void cMojangAPI::CacheUUIDToProfile(const AString & a_UUID)
+void cMojangAPI::CacheUUIDToProfile(const cUUID & a_UUID)
{
- ASSERT(a_UUID.size() == 32);
-
// Check if already present:
{
cCSLock Lock(m_CSUUIDToProfile);
@@ -814,11 +752,11 @@ void cMojangAPI::CacheUUIDToProfile(const AString & a_UUID)
-void cMojangAPI::QueryUUIDToProfile(const AString & a_UUID)
+void cMojangAPI::QueryUUIDToProfile(const cUUID & a_UUID)
{
// Create the request address:
AString Address = m_UUIDToProfileAddress;
- ReplaceString(Address, "%UUID%", a_UUID);
+ ReplaceString(Address, "%UUID%", a_UUID.ToShortString());
// Create the HTTP request:
AString Request;
@@ -909,7 +847,7 @@ void cMojangAPI::QueryUUIDToProfile(const AString & a_UUID)
-void cMojangAPI::NotifyNameUUID(const AString & a_PlayerName, const AString & a_UUID)
+void cMojangAPI::NotifyNameUUID(const AString & a_PlayerName, const cUUID & a_UUID)
{
// Notify the rank manager:
cCSLock Lock(m_CSRankMgr);
@@ -931,11 +869,11 @@ void cMojangAPI::Update(void)
AStringVector PlayerNames;
{
cCSLock Lock(m_CSNameToUUID);
- for (cProfileMap::const_iterator itr = m_NameToUUID.begin(), end = m_NameToUUID.end(); itr != end; ++itr)
+ for (const auto & NameToUUID : m_NameToUUID)
{
- if (itr->second.m_DateTime < LimitDateTime)
+ if (NameToUUID.second.m_DateTime < LimitDateTime)
{
- PlayerNames.push_back(itr->first);
+ PlayerNames.push_back(NameToUUID.first);
}
} // for itr - m_NameToUUID[]
}
@@ -946,23 +884,23 @@ void cMojangAPI::Update(void)
}
// Re-query all profiles that are stale:
- AStringVector ProfileUUIDs;
+ std::vector<cUUID> ProfileUUIDs;
{
cCSLock Lock(m_CSUUIDToProfile);
- for (cProfileMap::const_iterator itr = m_UUIDToProfile.begin(), end = m_UUIDToProfile.end(); itr != end; ++itr)
+ for (auto & UUIDToProfile : m_UUIDToProfile)
{
- if (itr->second.m_DateTime < LimitDateTime)
+ if (UUIDToProfile.second.m_DateTime < LimitDateTime)
{
- ProfileUUIDs.push_back(itr->first);
+ ProfileUUIDs.push_back(UUIDToProfile.first);
}
} // for itr - m_UUIDToProfile[]
}
if (!ProfileUUIDs.empty())
{
LOG("cMojangAPI: Updating uuid-to-profile cache for %u uuids", static_cast<unsigned>(ProfileUUIDs.size()));
- for (AStringVector::const_iterator itr = ProfileUUIDs.begin(), end = ProfileUUIDs.end(); itr != end; ++itr)
+ for (const auto & UUID : ProfileUUIDs)
{
- QueryUUIDToProfile(*itr);
+ QueryUUIDToProfile(UUID);
}
}
}
diff --git a/src/Protocol/MojangAPI.h b/src/Protocol/MojangAPI.h
index 3cd0376be..4d1751f1c 100644
--- a/src/Protocol/MojangAPI.h
+++ b/src/Protocol/MojangAPI.h
@@ -11,6 +11,8 @@
#include <time.h>
+#include "../UUID.h"
+
@@ -45,49 +47,38 @@ public:
Returns true if all was successful, false on failure. */
static bool SecureRequest(const AString & a_ServerName, const AString & a_Request, AString & a_Response);
- /** Normalizes the given UUID to its short form (32 bytes, no dashes, lowercase).
- Logs a warning and returns empty string if not a UUID.
- Note: only checks the string's length, not the actual content. */
- static AString MakeUUIDShort(const AString & a_UUID);
-
- /** Normalizes the given UUID to its dashed form (36 bytes, 4 dashes, lowercase).
- Logs a warning and returns empty string if not a UUID.
- Note: only checks the string's length, not the actual content. */
- static AString MakeUUIDDashed(const AString & a_UUID);
-
/** Converts a player name into a UUID.
- The UUID will be empty on error.
+ The UUID will be nil on error.
If a_UseOnlyCached is true, the function only consults the cached values.
If a_UseOnlyCached is false and the name is not found in the cache, it is looked up online, which is a blocking
operation, do not use this in world-tick thread!
If you have multiple names to resolve, use the GetUUIDsFromPlayerNames() function, it uses a single request for multiple names. */
- AString GetUUIDFromPlayerName(const AString & a_PlayerName, bool a_UseOnlyCached = false);
+ cUUID GetUUIDFromPlayerName(const AString & a_PlayerName, bool a_UseOnlyCached = false);
/** Converts a UUID into a playername.
The returned playername will be empty on error.
- Both short and dashed UUID formats are accepted.
Uses both m_UUIDToName and m_UUIDToProfile to search for the value. Uses m_UUIDToProfile for cache.
If a_UseOnlyCached is true, the function only consults the cached values.
If a_UseOnlyCached is false and the name is not found in the cache, it is looked up online, which is a blocking
operation, do not use this in world-tick thread! */
- AString GetPlayerNameFromUUID(const AString & a_UUID, bool a_UseOnlyCached = false);
+ AString GetPlayerNameFromUUID(const cUUID & a_UUID, bool a_UseOnlyCached = false);
/** Converts the player names into UUIDs.
a_PlayerName[idx] will be converted to UUID and returned as idx-th value
- The UUID will be empty on error.
+ The UUID will be nil on error.
If a_UseOnlyCached is true, only the cached values are returned.
If a_UseOnlyCached is false, the names not found in the cache are looked up online, which is a blocking
operation, do not use this in world-tick thread! */
- AStringVector GetUUIDsFromPlayerNames(const AStringVector & a_PlayerName, bool a_UseOnlyCached = false);
+ std::vector<cUUID> GetUUIDsFromPlayerNames(const AStringVector & a_PlayerName, bool a_UseOnlyCached = false);
/** Called by the Authenticator to add a PlayerName -> UUID mapping that it has received from
authenticating a user. This adds the cache item and "refreshes" it if existing, adjusting its datetime
stamp to now. */
- void AddPlayerNameToUUIDMapping(const AString & a_PlayerName, const AString & a_UUID);
+ void AddPlayerNameToUUIDMapping(const AString & a_PlayerName, const cUUID & a_UUID);
/** Called by the Authenticator to add a profile that it has received from authenticating a user. Adds
the profile to the respective mapping caches and updtes their datetime stamp to now. */
- void AddPlayerProfile(const AString & a_PlayerName, const AString & a_UUID, const Json::Value & a_Properties);
+ void AddPlayerProfile(const AString & a_PlayerName, const cUUID & a_UUID, const Json::Value & a_Properties);
/** Sets the m_RankMgr that is used for name-uuid notifications. Accepts nullptr to remove the binding. */
void SetRankManager(cRankManager * a_RankManager) { m_RankMgr = a_RankManager; }
@@ -101,7 +92,7 @@ protected:
struct sProfile
{
AString m_PlayerName; // Case-correct playername
- AString m_UUID; // Short lowercased UUID
+ cUUID m_UUID; // Player UUID
AString m_Textures; // The Textures field of the profile properties
AString m_TexturesSignature; // The signature of the Textures field of the profile properties
Int64 m_DateTime; // UNIXtime of the profile lookup
@@ -119,7 +110,7 @@ protected:
/** Constructor for the storage creation. */
sProfile(
const AString & a_PlayerName,
- const AString & a_UUID,
+ const cUUID & a_UUID,
const AString & a_Textures,
const AString & a_TexturesSignature,
Int64 a_DateTime
@@ -135,12 +126,13 @@ protected:
/** Constructor that parses the values from the Json profile. */
sProfile(
const AString & a_PlayerName,
- const AString & a_UUID,
+ const cUUID & a_UUID,
const Json::Value & a_Properties,
Int64 a_DateTime
);
};
typedef std::map<AString, sProfile> cProfileMap;
+ typedef std::map<cUUID, sProfile> cUUIDProfileMap;
/** The server to connect to when converting player names to UUIDs. For example "api.mojang.com". */
@@ -164,14 +156,14 @@ protected:
cCriticalSection m_CSNameToUUID;
/** Cache for the Name-to-UUID lookups. The map key is lowercased short UUID. Protected by m_CSUUIDToName. */
- cProfileMap m_UUIDToName;
+ cUUIDProfileMap m_UUIDToName;
/** Protects m_UUIDToName against simultaneous multi-threaded access. */
cCriticalSection m_CSUUIDToName;
/** Cache for the UUID-to-profile lookups. The map key is lowercased short UUID.
Protected by m_CSUUIDToProfile. */
- cProfileMap m_UUIDToProfile;
+ cUUIDProfileMap m_UUIDToProfile;
/** Protects m_UUIDToProfile against simultaneous multi-threaded access. */
cCriticalSection m_CSUUIDToProfile;
@@ -204,18 +196,16 @@ protected:
void QueryNamesToUUIDs(AStringVector & a_PlayerNames);
/** Makes sure the specified UUID is in the m_UUIDToProfile cache. If missing, downloads it from Mojang API servers.
- UUIDs that are not valid will not be added into the cache.
- ASSUMEs that a_UUID is a lowercased short UUID. */
- void CacheUUIDToProfile(const AString & a_UUID);
+ UUIDs that are not valid will not be added into the cache. */
+ void CacheUUIDToProfile(const cUUID & a_UUID);
/** Queries the specified UUID's profile and stores it in the m_UUIDToProfile cache. If already present, updates the cache entry.
- UUIDs that are not valid will not be added into the cache.
- ASSUMEs that a_UUID is a lowercased short UUID. */
- void QueryUUIDToProfile(const AString & a_UUID);
+ UUIDs that are not valid will not be added into the cache. */
+ void QueryUUIDToProfile(const cUUID & a_UUID);
/** Called for each name-uuid pairing that is discovered.
If assigned, notifies the m_RankManager of the event. */
- void NotifyNameUUID(const AString & a_PlayerName, const AString & a_PlayerUUID);
+ void NotifyNameUUID(const AString & a_PlayerName, const cUUID & a_PlayerUUID);
/** Updates the stale values in the DB from the Mojang servers. Called from the cUpdateThread, blocks on the HTTPS API calls. */
void Update(void);
diff --git a/src/Protocol/Packetizer.cpp b/src/Protocol/Packetizer.cpp
index 0a84d4678..5cae1fad5 100644
--- a/src/Protocol/Packetizer.cpp
+++ b/src/Protocol/Packetizer.cpp
@@ -5,46 +5,7 @@
#include "Globals.h"
#include "Packetizer.h"
-
-
-
-
-
-/** Converts the hex digit character to its value. */
-static UInt8 HexDigitValue(char a_Character)
-{
- switch (a_Character)
- {
- case '0': return 0;
- case '1': return 1;
- case '2': return 2;
- case '3': return 3;
- case '4': return 4;
- case '5': return 5;
- case '6': return 6;
- case '7': return 7;
- case '8': return 8;
- case '9': return 9;
- case 'a': return 10;
- case 'b': return 11;
- case 'c': return 12;
- case 'd': return 13;
- case 'e': return 14;
- case 'f': return 15;
- case 'A': return 10;
- case 'B': return 11;
- case 'C': return 12;
- case 'D': return 13;
- case 'E': return 14;
- case 'F': return 15;
- default:
- {
- LOGWARNING("Bad hex digit: %c", a_Character);
- ASSERT(!"Bad hex digit");
- return 0;
- }
- }
-}
+#include "UUID.h"
@@ -80,18 +41,10 @@ void cPacketizer::WriteFPInt(double a_Value)
-void cPacketizer::WriteUUID(const AString & a_UUID)
+void cPacketizer::WriteUUID(const cUUID & a_UUID)
{
- if (a_UUID.length() != 32)
- {
- LOGWARNING("%s: Attempt to send a bad uuid (length isn't 32): %s", __FUNCTION__, a_UUID.c_str());
- ASSERT(!"Wrong uuid length!");
- return;
- }
-
- for (size_t i = 0; i < 32; i += 2)
+ for (auto val : a_UUID.ToRaw())
{
- auto val = static_cast<UInt8>(HexDigitValue(a_UUID[i]) << 4 | HexDigitValue(a_UUID[i + 1]));
VERIFY(m_Out.WriteBEUInt8(val));
}
}
diff --git a/src/Protocol/Packetizer.h b/src/Protocol/Packetizer.h
index 26b3a7ec7..6d2284976 100644
--- a/src/Protocol/Packetizer.h
+++ b/src/Protocol/Packetizer.h
@@ -17,6 +17,10 @@
class cByteBuffer;
+// fwd:
+class cUUID;
+
+
@@ -134,7 +138,7 @@ public:
void WriteFPInt(double a_Value);
/** Writes the specified UUID as a 128-bit BigEndian integer. */
- void WriteUUID(const AString & a_UUID);
+ void WriteUUID(const cUUID & a_UUID);
UInt32 GetPacketType(void) const { return m_PacketType; }
diff --git a/src/Protocol/Protocol_1_10.cpp b/src/Protocol/Protocol_1_10.cpp
index 650f9dd32..67b76872a 100644
--- a/src/Protocol/Protocol_1_10.cpp
+++ b/src/Protocol/Protocol_1_10.cpp
@@ -619,7 +619,7 @@ void cProtocol_1_10_0::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity
// The new Block Entity format for a Mob Head. See: https://minecraft.gamepedia.com/Head#Block_entity
Writer.BeginCompound("Owner");
- Writer.AddString("Id", MobHeadEntity.GetOwnerUUID());
+ Writer.AddString("Id", MobHeadEntity.GetOwnerUUID().ToShortString());
Writer.AddString("Name", MobHeadEntity.GetOwnerName());
Writer.BeginCompound("Properties");
Writer.BeginList("textures", TAG_Compound);
diff --git a/src/Protocol/Protocol_1_11.cpp b/src/Protocol/Protocol_1_11.cpp
index 9212e97ed..c562503bd 100644
--- a/src/Protocol/Protocol_1_11.cpp
+++ b/src/Protocol/Protocol_1_11.cpp
@@ -466,7 +466,7 @@ void cProtocol_1_11_0::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity
// The new Block Entity format for a Mob Head. See: https://minecraft.gamepedia.com/Head#Block_entity
Writer.BeginCompound("Owner");
- Writer.AddString("Id", MobHeadEntity.GetOwnerUUID());
+ Writer.AddString("Id", MobHeadEntity.GetOwnerUUID().ToShortString());
Writer.AddString("Name", MobHeadEntity.GetOwnerName());
Writer.BeginCompound("Properties");
Writer.BeginList("textures", TAG_Compound);
diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp
index 3e2f084c7..42e69fd43 100644
--- a/src/Protocol/Protocol_1_8.cpp
+++ b/src/Protocol/Protocol_1_8.cpp
@@ -22,6 +22,7 @@ Implements the 1.8 protocol classes:
#include "../StringCompression.h"
#include "../CompositeChat.h"
#include "../Statistics.h"
+#include "../UUID.h"
#include "../WorldStorage/FastNBT.h"
#include "../WorldStorage/EnchantmentSerializer.h"
@@ -118,7 +119,11 @@ cProtocol_1_8_0::cProtocol_1_8_0(cClientHandle * a_Client, const AString & a_Ser
LOGD("Player at %s connected via BungeeCord", Params[1].c_str());
m_ServerAddress = Params[0];
m_Client->SetIPString(Params[1]);
- m_Client->SetUUID(cMojangAPI::MakeUUIDShort(Params[2]));
+
+ cUUID UUID;
+ UUID.FromString(Params[2]);
+ m_Client->SetUUID(UUID);
+
m_Client->SetProperties(Params[3]);
}
@@ -705,7 +710,7 @@ void cProtocol_1_8_0::SendLoginSuccess(void)
{
cPacketizer Pkt(*this, 0x02); // Login success packet
- Pkt.WriteString(cMojangAPI::MakeUUIDDashed(m_Client->GetUUID()));
+ Pkt.WriteString(m_Client->GetUUID().ToLongString());
Pkt.WriteString(m_Client->GetUsername());
}
}
@@ -1071,7 +1076,7 @@ void cProtocol_1_8_0::SendPlayerSpawn(const cPlayer & a_Player)
// Called to spawn another player for the client
cPacketizer Pkt(*this, 0x0c); // Spawn Player packet
Pkt.WriteVarInt32(a_Player.GetUniqueID());
- Pkt.WriteUUID(cMojangAPI::MakeUUIDShort(a_Player.GetUUID()));
+ Pkt.WriteUUID(a_Player.GetUUID());
Pkt.WriteFPInt(a_Player.GetPosX());
Pkt.WriteFPInt(a_Player.GetPosY() + 0.001); // The "+ 0.001" is there because otherwise the player falls through the block they were standing on.
Pkt.WriteFPInt(a_Player.GetPosZ());
@@ -2551,7 +2556,7 @@ void cProtocol_1_8_0::HandlePacketSlotSelect(cByteBuffer & a_ByteBuffer)
void cProtocol_1_8_0::HandlePacketSpectate(cByteBuffer &a_ByteBuffer)
{
- AString playerUUID;
+ cUUID playerUUID;
if (!a_ByteBuffer.ReadUUID(playerUUID))
{
return;
@@ -3183,7 +3188,7 @@ void cProtocol_1_8_0::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity &
// The new Block Entity format for a Mob Head. See: https://minecraft.gamepedia.com/Head#Block_entity
Writer.BeginCompound("Owner");
- Writer.AddString("Id", MobHeadEntity.GetOwnerUUID());
+ Writer.AddString("Id", MobHeadEntity.GetOwnerUUID().ToShortString());
Writer.AddString("Name", MobHeadEntity.GetOwnerName());
Writer.BeginCompound("Properties");
Writer.BeginList("textures", TAG_Compound);
diff --git a/src/Protocol/Protocol_1_9.cpp b/src/Protocol/Protocol_1_9.cpp
index 7921d3e36..0c5ac58f6 100644
--- a/src/Protocol/Protocol_1_9.cpp
+++ b/src/Protocol/Protocol_1_9.cpp
@@ -133,7 +133,11 @@ cProtocol_1_9_0::cProtocol_1_9_0(cClientHandle * a_Client, const AString & a_Ser
LOGD("Player at %s connected via BungeeCord", Params[1].c_str());
m_ServerAddress = Params[0];
m_Client->SetIPString(Params[1]);
- m_Client->SetUUID(cMojangAPI::MakeUUIDShort(Params[2]));
+
+ cUUID UUID;
+ UUID.FromString(Params[2]);
+ m_Client->SetUUID(UUID);
+
m_Client->SetProperties(Params[3]);
}
@@ -720,7 +724,7 @@ void cProtocol_1_9_0::SendLoginSuccess(void)
{
cPacketizer Pkt(*this, 0x02); // Login success packet
- Pkt.WriteString(cMojangAPI::MakeUUIDDashed(m_Client->GetUUID()));
+ Pkt.WriteString(m_Client->GetUUID().ToLongString());
Pkt.WriteString(m_Client->GetUsername());
}
}
@@ -1094,7 +1098,7 @@ void cProtocol_1_9_0::SendPlayerSpawn(const cPlayer & a_Player)
// Called to spawn another player for the client
cPacketizer Pkt(*this, 0x05); // Spawn Player packet
Pkt.WriteVarInt32(a_Player.GetUniqueID());
- Pkt.WriteUUID(cMojangAPI::MakeUUIDShort(a_Player.GetUUID()));
+ Pkt.WriteUUID(a_Player.GetUUID());
Pkt.WriteBEDouble(a_Player.GetPosX());
Pkt.WriteBEDouble(a_Player.GetPosY() + 0.001); // The "+ 0.001" is there because otherwise the player falls through the block they were standing on.
Pkt.WriteBEDouble(a_Player.GetPosZ());
@@ -2624,7 +2628,7 @@ void cProtocol_1_9_0::HandlePacketSlotSelect(cByteBuffer & a_ByteBuffer)
void cProtocol_1_9_0::HandlePacketSpectate(cByteBuffer & a_ByteBuffer)
{
- AString playerUUID;
+ cUUID playerUUID;
if (!a_ByteBuffer.ReadUUID(playerUUID))
{
return;
@@ -3513,7 +3517,7 @@ void cProtocol_1_9_0::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity &
// The new Block Entity format for a Mob Head. See: https://minecraft.gamepedia.com/Head#Block_entity
Writer.BeginCompound("Owner");
- Writer.AddString("Id", MobHeadEntity.GetOwnerUUID());
+ Writer.AddString("Id", MobHeadEntity.GetOwnerUUID().ToShortString());
Writer.AddString("Name", MobHeadEntity.GetOwnerName());
Writer.BeginCompound("Properties");
Writer.BeginList("textures", TAG_Compound);
diff --git a/src/RankManager.cpp b/src/RankManager.cpp
index 0c6ef508e..53083fa7a 100644
--- a/src/RankManager.cpp
+++ b/src/RankManager.cpp
@@ -92,10 +92,10 @@ protected:
AStringVector m_Groups;
/** Assigned by ResolveUserUUIDs(), contains the online (Mojang) UUID of the player. */
- AString m_UUID;
+ cUUID m_UUID;
/** Assigned by ResolveUserUUIDs(), contains the offline (generated) UUID of the player. */
- AString m_OfflineUUID;
+ cUUID m_OfflineUUID;
sUser(void) {}
@@ -282,15 +282,15 @@ protected:
m_MojangAPI.GetUUIDsFromPlayerNames(PlayerNames);
// Assign the UUIDs back to players, remove those not resolved:
- for (sUserMap::iterator itr = m_Users.begin(); itr != m_Users.end(); ++itr)
+ for (auto & User : m_Users)
{
- AString UUID = m_MojangAPI.GetUUIDFromPlayerName(itr->second.m_Name);
- if (UUID.empty())
+ cUUID UUID = m_MojangAPI.GetUUIDFromPlayerName(User.second.m_Name);
+ if (UUID.IsNil())
{
- LOGWARNING("RankMigrator: Cannot resolve player %s to online UUID, player will be left unranked in online mode", itr->second.m_Name.c_str());
+ LOGWARNING("RankMigrator: Cannot resolve player %s to online UUID, player will be left unranked in online mode", User.second.m_Name.c_str());
}
- itr->second.m_UUID = UUID;
- itr->second.m_OfflineUUID = cClientHandle::GenerateOfflineUUID(itr->second.m_Name);
+ User.second.m_UUID = UUID;
+ User.second.m_OfflineUUID = cClientHandle::GenerateOfflineUUID(User.second.m_Name);
}
}
@@ -469,7 +469,7 @@ void cRankManager::Initialize(cMojangAPI & a_MojangAPI)
-AString cRankManager::GetPlayerRankName(const AString & a_PlayerUUID)
+AString cRankManager::GetPlayerRankName(const cUUID & a_PlayerUUID)
{
ASSERT(m_IsInitialized);
cCSLock Lock(m_CS);
@@ -477,7 +477,7 @@ AString cRankManager::GetPlayerRankName(const AString & a_PlayerUUID)
try
{
SQLite::Statement stmt(m_DB, "SELECT Rank.Name FROM Rank LEFT JOIN PlayerRank ON Rank.RankID = PlayerRank.RankID WHERE PlayerRank.PlayerUUID = ?");
- stmt.bind(1, a_PlayerUUID);
+ stmt.bind(1, a_PlayerUUID.ToShortString());
// executeStep returns false on no data
if (!stmt.executeStep())
{
@@ -497,7 +497,7 @@ AString cRankManager::GetPlayerRankName(const AString & a_PlayerUUID)
-AString cRankManager::GetPlayerName(const AString & a_PlayerUUID)
+AString cRankManager::GetPlayerName(const cUUID & a_PlayerUUID)
{
ASSERT(m_IsInitialized);
cCSLock Lock(m_CS);
@@ -506,7 +506,7 @@ AString cRankManager::GetPlayerName(const AString & a_PlayerUUID)
{
// Prepare the DB statement:
SQLite::Statement stmt(m_DB, "SELECT PlayerName FROM PlayerRank WHERE PlayerUUID = ?");
- stmt.bind(1, a_PlayerUUID);
+ stmt.bind(1, a_PlayerUUID.ToShortString());
if (stmt.executeStep())
{
@@ -524,7 +524,7 @@ AString cRankManager::GetPlayerName(const AString & a_PlayerUUID)
-AStringVector cRankManager::GetPlayerGroups(const AString & a_PlayerUUID)
+AStringVector cRankManager::GetPlayerGroups(const cUUID & a_PlayerUUID)
{
ASSERT(m_IsInitialized);
cCSLock Lock(m_CS);
@@ -539,7 +539,7 @@ AStringVector cRankManager::GetPlayerGroups(const AString & a_PlayerUUID)
"LEFT JOIN PlayerRank ON PlayerRank.RankID = RankPermGroup.RankID "
"WHERE PlayerRank.PlayerUUID = ?"
);
- stmt.bind(1, a_PlayerUUID);
+ stmt.bind(1, a_PlayerUUID.ToShortString());
// Execute and get results:
while (stmt.executeStep())
@@ -558,7 +558,7 @@ AStringVector cRankManager::GetPlayerGroups(const AString & a_PlayerUUID)
-AStringVector cRankManager::GetPlayerPermissions(const AString & a_PlayerUUID)
+AStringVector cRankManager::GetPlayerPermissions(const cUUID & a_PlayerUUID)
{
AString Rank = GetPlayerRankName(a_PlayerUUID);
if (Rank.empty())
@@ -572,7 +572,7 @@ AStringVector cRankManager::GetPlayerPermissions(const AString & a_PlayerUUID)
-AStringVector cRankManager::GetPlayerRestrictions(const AString & a_PlayerUUID)
+AStringVector cRankManager::GetPlayerRestrictions(const cUUID & a_PlayerUUID)
{
AString Rank = GetPlayerRankName(a_PlayerUUID);
if (Rank.empty())
@@ -739,18 +739,24 @@ AStringVector cRankManager::GetRankRestrictions(const AString & a_RankName)
-AStringVector cRankManager::GetAllPlayerUUIDs(void)
+std::vector<cUUID> cRankManager::GetAllPlayerUUIDs(void)
{
ASSERT(m_IsInitialized);
cCSLock Lock(m_CS);
- AStringVector res;
+ cUUID tempUUID;
+ std::vector<cUUID> res;
try
{
SQLite::Statement stmt(m_DB, "SELECT PlayerUUID FROM PlayerRank ORDER BY PlayerName COLLATE NOCASE");
while (stmt.executeStep())
{
- res.push_back(stmt.getColumn(0).getText());
+ if (!tempUUID.FromString(stmt.getColumn(0).getText()))
+ {
+ // Invalid UUID, ignore
+ continue;
+ }
+ res.push_back(tempUUID);
}
}
catch (const SQLite::Exception & ex)
@@ -881,7 +887,7 @@ AStringVector cRankManager::GetAllPermissionsRestrictions(void)
bool cRankManager::GetPlayerMsgVisuals(
- const AString & a_PlayerUUID,
+ const cUUID & a_PlayerUUID,
AString & a_MsgPrefix,
AString & a_MsgSuffix,
AString & a_MsgNameColorCode
@@ -1746,11 +1752,13 @@ bool cRankManager::RenameGroup(const AString & a_OldName, const AString & a_NewN
-void cRankManager::SetPlayerRank(const AString & a_PlayerUUID, const AString & a_PlayerName, const AString & a_RankName)
+void cRankManager::SetPlayerRank(const cUUID & a_PlayerUUID, const AString & a_PlayerName, const AString & a_RankName)
{
ASSERT(m_IsInitialized);
cCSLock Lock(m_CS);
+ AString StrUUID = a_PlayerUUID.ToShortString();
+
try
{
// Get the rank ID:
@@ -1771,7 +1779,7 @@ void cRankManager::SetPlayerRank(const AString & a_PlayerUUID, const AString & a
SQLite::Statement stmt(m_DB, "UPDATE PlayerRank SET RankID = ?, PlayerName = ? WHERE PlayerUUID = ?");
stmt.bind(1, RankID);
stmt.bind(2, a_PlayerName);
- stmt.bind(3, a_PlayerUUID);
+ stmt.bind(3, StrUUID);
if (stmt.exec() > 0)
{
// Successfully updated the player's rank
@@ -1782,7 +1790,7 @@ void cRankManager::SetPlayerRank(const AString & a_PlayerUUID, const AString & a
// The player is not yet in the DB, add them:
SQLite::Statement stmt(m_DB, "INSERT INTO PlayerRank (RankID, PlayerUUID, PlayerName) VALUES (?, ?, ?)");
stmt.bind(1, RankID);
- stmt.bind(2, a_PlayerUUID);
+ stmt.bind(2, StrUUID);
stmt.bind(3, a_PlayerName);
if (stmt.exec() > 0)
{
@@ -1791,13 +1799,13 @@ void cRankManager::SetPlayerRank(const AString & a_PlayerUUID, const AString & a
}
LOGWARNING("%s: Failed to set player UUID %s to rank %s.",
- __FUNCTION__, a_PlayerUUID.c_str(), a_RankName.c_str()
+ __FUNCTION__, StrUUID.c_str(), a_RankName.c_str()
);
}
catch (const SQLite::Exception & ex)
{
LOGWARNING("%s: Failed to set player UUID %s to rank %s: %s",
- __FUNCTION__, a_PlayerUUID.c_str(), a_RankName.c_str(), ex.what()
+ __FUNCTION__, StrUUID.c_str(), a_RankName.c_str(), ex.what()
);
}
}
@@ -1806,21 +1814,23 @@ void cRankManager::SetPlayerRank(const AString & a_PlayerUUID, const AString & a
-void cRankManager::RemovePlayerRank(const AString & a_PlayerUUID)
+void cRankManager::RemovePlayerRank(const cUUID & a_PlayerUUID)
{
ASSERT(m_IsInitialized);
cCSLock Lock(m_CS);
+ AString StrUUID = a_PlayerUUID.ToShortString();
+
try
{
SQLite::Statement stmt(m_DB, "DELETE FROM PlayerRank WHERE PlayerUUID = ?");
- stmt.bind(1, a_PlayerUUID);
+ stmt.bind(1, StrUUID);
stmt.exec();
}
catch (const SQLite::Exception & ex)
{
LOGWARNING("%s: Failed to remove rank from player UUID %s: %s",
- __FUNCTION__, a_PlayerUUID.c_str(), ex.what()
+ __FUNCTION__, StrUUID.c_str(), ex.what()
);
}
}
@@ -1948,15 +1958,17 @@ bool cRankManager::GroupExists(const AString & a_GroupName)
-bool cRankManager::IsPlayerRankSet(const AString & a_PlayerUUID)
+bool cRankManager::IsPlayerRankSet(const cUUID & a_PlayerUUID)
{
ASSERT(m_IsInitialized);
cCSLock Lock(m_CS);
+ AString StrUUID = a_PlayerUUID.ToShortString();
+
try
{
SQLite::Statement stmt(m_DB, "SELECT * FROM PlayerRank WHERE PlayerUUID = ?");
- stmt.bind(1, a_PlayerUUID);
+ stmt.bind(1, StrUUID);
if (stmt.executeStep())
{
// The player UUID was found, they have a rank
@@ -1965,7 +1977,7 @@ bool cRankManager::IsPlayerRankSet(const AString & a_PlayerUUID)
}
catch (const SQLite::Exception & ex)
{
- LOGWARNING("%s: Failed to query DB for player UUID %s: %s", __FUNCTION__, a_PlayerUUID.c_str(), ex.what());
+ LOGWARNING("%s: Failed to query DB for player UUID %s: %s", __FUNCTION__, StrUUID.c_str(), ex.what());
}
return false;
}
@@ -2068,7 +2080,7 @@ bool cRankManager::IsRestrictionInGroup(const AString & a_Restriction, const ASt
-void cRankManager::NotifyNameUUID(const AString & a_PlayerName, const AString & a_UUID)
+void cRankManager::NotifyNameUUID(const AString & a_PlayerName, const cUUID & a_UUID)
{
ASSERT(m_IsInitialized);
cCSLock Lock(m_CS);
@@ -2077,7 +2089,7 @@ void cRankManager::NotifyNameUUID(const AString & a_PlayerName, const AString &
{
SQLite::Statement stmt(m_DB, "UPDATE PlayerRank SET PlayerName = ? WHERE PlayerUUID = ?");
stmt.bind(1, a_PlayerName);
- stmt.bind(2, a_UUID);
+ stmt.bind(2, a_UUID.ToShortString());
stmt.exec();
}
catch (const SQLite::Exception & ex)
@@ -2161,16 +2173,18 @@ void cRankManager::ClearPlayerRanks(void)
-bool cRankManager::UpdatePlayerName(const AString & a_PlayerUUID, const AString & a_NewPlayerName)
+bool cRankManager::UpdatePlayerName(const cUUID & a_PlayerUUID, const AString & a_NewPlayerName)
{
ASSERT(m_IsInitialized);
cCSLock Lock(m_CS);
+ AString StrUUID = a_PlayerUUID.ToShortString();
+
try
{
SQLite::Statement stmt(m_DB, "UPDATE PlayerRank SET PlayerName = ? WHERE PlayerUUID = ?");
stmt.bind(1, a_NewPlayerName);
- stmt.bind(2, a_PlayerUUID);
+ stmt.bind(2, StrUUID);
if (stmt.exec() > 0)
{
// The player name was changed, returns true
@@ -2179,7 +2193,7 @@ bool cRankManager::UpdatePlayerName(const AString & a_PlayerUUID, const AString
}
catch (const SQLite::Exception & ex)
{
- LOGWARNING("%s: Failed to update player name from UUID %s: %s", __FUNCTION__, a_PlayerUUID.c_str(), ex.what());
+ LOGWARNING("%s: Failed to update player name from UUID %s: %s", __FUNCTION__, StrUUID.c_str(), ex.what());
}
return false;
}
diff --git a/src/RankManager.h b/src/RankManager.h
index 73d94a5a7..abe860b1c 100644
--- a/src/RankManager.h
+++ b/src/RankManager.h
@@ -14,7 +14,7 @@
-
+class cUUID;
class cMojangAPI;
@@ -58,22 +58,22 @@ public:
/** Returns the name of the rank that the specified player has assigned to them.
If the player has no rank assigned, returns an empty string (NOT the default rank). */
- AString GetPlayerRankName(const AString & a_PlayerUUID);
+ AString GetPlayerRankName(const cUUID & a_PlayerUUID);
/** Returns the last name that the specified player has.
An empty string is returned if the player isn't in the database. */
- AString GetPlayerName(const AString & a_PlayerUUID);
+ AString GetPlayerName(const cUUID & a_PlayerUUID);
/** Returns the names of Groups that the specified player has assigned to them. */
- AStringVector GetPlayerGroups(const AString & a_PlayerUUID);
+ AStringVector GetPlayerGroups(const cUUID & a_PlayerUUID);
/** Returns the permissions that the specified player has assigned to them.
If the player has no rank assigned to them, returns the default rank's permissions. */
- AStringVector GetPlayerPermissions(const AString & a_PlayerUUID);
+ AStringVector GetPlayerPermissions(const cUUID & a_PlayerUUID);
/** Returns the restrictions that the specified player has assigned to them.
If the player has no rank assigned to them, returns the default rank's restrictions. */
- AStringVector GetPlayerRestrictions(const AString & a_PlayerUUID);
+ AStringVector GetPlayerRestrictions(const cUUID & a_PlayerUUID);
/** Returns the names of groups that the specified rank has assigned to it.
Returns an empty vector if the rank doesn't exist. */
@@ -95,8 +95,8 @@ public:
Returns an empty vector if the rank doesn't exist. Any non-existent groups are ignored. */
AStringVector GetRankRestrictions(const AString & a_RankName);
- /** Returns the short uuids of all defined players. The returned players are ordered by their name (NOT their UUIDs). */
- AStringVector GetAllPlayerUUIDs(void);
+ /** Returns the uuids of all defined players. The returned players are ordered by their name (NOT their UUIDs). */
+ std::vector<cUUID> GetAllPlayerUUIDs(void);
/** Returns the names of all defined ranks. */
AStringVector GetAllRanks(void);
@@ -116,7 +116,7 @@ public:
/** Returns the message visuals (prefix, postfix, color) for the specified player.
Returns true if the visuals were read from the DB, false if not (player not found etc). */
bool GetPlayerMsgVisuals(
- const AString & a_PlayerUUID,
+ const cUUID & a_PlayerUUID,
AString & a_MsgPrefix,
AString & a_MsgSuffix,
AString & a_MsgNameColorCode
@@ -199,13 +199,13 @@ public:
Note that this doesn't change the cPlayer if the player is already connected, you need to update all the
cPlayer instances manually.
The PlayerName is provided for reference, so that GetRankPlayerNames() can work. */
- void SetPlayerRank(const AString & a_PlayerUUID, const AString & a_PlayerName, const AString & a_RankName);
+ void SetPlayerRank(const cUUID & a_PlayerUUID, const AString & a_PlayerName, const AString & a_RankName);
/** Removes the player's rank assignment. The player is left without a rank.
Note that this doesn't change the cPlayer instances for the already connected players, you need to update
all the instances manually.
No action if the player has no rank assigned to them already. */
- void RemovePlayerRank(const AString & a_PlayerUUID);
+ void RemovePlayerRank(const cUUID & a_PlayerUUID);
/** Sets the message visuals of an existing rank. No action if the rank name is not found. */
void SetRankVisuals(
@@ -231,7 +231,7 @@ public:
bool GroupExists(const AString & a_GroupName);
/** Returns true iff the specified player has a rank assigned to them in the DB. */
- bool IsPlayerRankSet(const AString & a_PlayerUUID);
+ bool IsPlayerRankSet(const cUUID & a_PlayerUUID);
/** Returns true iff the specified rank contains the specified group. */
bool IsGroupInRank(const AString & a_GroupName, const AString & a_RankName);
@@ -243,7 +243,7 @@ public:
bool IsRestrictionInGroup(const AString & a_Restriction, const AString & a_GroupName);
/** Called by cMojangAPI whenever the playername-uuid pairing is discovered. Updates the DB. */
- void NotifyNameUUID(const AString & a_PlayerName, const AString & a_UUID);
+ void NotifyNameUUID(const AString & a_PlayerName, const cUUID & a_UUID);
/** Sets the specified rank as the default rank.
Returns true on success, false on failure (rank not found). */
@@ -257,7 +257,7 @@ public:
void ClearPlayerRanks(void);
/** Updates the playername that is saved with this uuid. Returns false if a error occurred */
- bool UpdatePlayerName(const AString & a_PlayerUUID, const AString & a_NewPlayerName);
+ bool UpdatePlayerName(const cUUID & a_PlayerUUID, const AString & a_NewPlayerName);
protected:
diff --git a/src/Root.cpp b/src/Root.cpp
index a487310a8..3e30d8a07 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -676,7 +676,7 @@ void cRoot::KickUser(int a_ClientID, const AString & a_Reason)
-void cRoot::AuthenticateUser(int a_ClientID, const AString & a_Name, const AString & a_UUID, const Json::Value & a_Properties)
+void cRoot::AuthenticateUser(int a_ClientID, const AString & a_Name, const cUUID & a_UUID, const Json::Value & a_Properties)
{
m_Server->AuthenticateUser(a_ClientID, a_Name, a_UUID, a_Properties);
}
@@ -820,7 +820,7 @@ bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallbac
-bool cRoot::DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallback & a_Callback)
+bool cRoot::DoWithPlayerByUUID(const cUUID & a_PlayerUUID, cPlayerListCallback & a_Callback)
{
for (WorldMap::iterator itr = m_WorldsByName.begin(); itr != m_WorldsByName.end(); ++itr)
{
diff --git a/src/Root.h b/src/Root.h
index 23eeb8c80..44567018d 100644
--- a/src/Root.h
+++ b/src/Root.h
@@ -25,6 +25,7 @@ class cCommandOutputCallback;
class cCompositeChat;
class cSettingsRepositoryInterface;
class cDeadlockDetect;
+class cUUID;
typedef cItemCallback<cPlayer> cPlayerListCallback;
typedef cItemCallback<cWorld> cWorldListCallback;
@@ -123,7 +124,7 @@ public:
void KickUser(int a_ClientID, const AString & a_Reason);
/** Called by cAuthenticator to auth the specified user */
- void AuthenticateUser(int a_ClientID, const AString & a_Name, const AString & a_UUID, const Json::Value & a_Properties);
+ void AuthenticateUser(int a_ClientID, const AString & a_Name, const cUUID & a_UUID, const Json::Value & a_Properties);
/** Executes commands queued in the command queue */
void TickCommands(void);
@@ -141,7 +142,7 @@ public:
bool FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
/** Finds the player over his uuid and calls the callback */
- bool DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
+ bool DoWithPlayerByUUID(const cUUID & 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);
diff --git a/src/Server.cpp b/src/Server.cpp
index a8703be86..70d594f2d 100644
--- a/src/Server.cpp
+++ b/src/Server.cpp
@@ -622,7 +622,7 @@ void cServer::KickUser(int a_ClientID, const AString & a_Reason)
-void cServer::AuthenticateUser(int a_ClientID, const AString & a_Name, const AString & a_UUID, const Json::Value & a_Properties)
+void cServer::AuthenticateUser(int a_ClientID, const AString & a_Name, const cUUID & a_UUID, const Json::Value & a_Properties)
{
cCSLock Lock(m_CSClients);
diff --git a/src/Server.h b/src/Server.h
index 2ac530c1e..633f6de70 100644
--- a/src/Server.h
+++ b/src/Server.h
@@ -39,6 +39,7 @@ typedef std::list<cClientHandlePtr> cClientHandlePtrs;
typedef std::list<cClientHandle *> cClientHandles;
class cCommandOutputCallback;
class cSettingsRepositoryInterface;
+class cUUID;
namespace Json
@@ -101,7 +102,7 @@ public:
void KickUser(int a_ClientID, const AString & a_Reason);
/** Authenticates the specified user, called by cAuthenticator */
- void AuthenticateUser(int a_ClientID, const AString & a_Name, const AString & a_UUID, const Json::Value & a_Properties);
+ void AuthenticateUser(int a_ClientID, const AString & a_Name, const cUUID & a_UUID, const Json::Value & a_Properties);
const AString & GetServerID(void) const { return m_ServerID; } // tolua_export
diff --git a/src/UUID.cpp b/src/UUID.cpp
new file mode 100644
index 000000000..e150b3603
--- /dev/null
+++ b/src/UUID.cpp
@@ -0,0 +1,283 @@
+// UUID.h
+
+// Defines the cUUID class representing a Universally Unique Identifier
+
+#include "Globals.h"
+#include "UUID.h"
+
+#include "polarssl/md5.h"
+
+
+/** UUID normalised in textual form. */
+struct sShortUUID
+{
+ char Data[32]{};
+ bool IsValid = false;
+};
+
+/** Returns the given UUID in shortened form with IsValid indicating success.
+Doesn't check digits are hexadecimal but does check dashes if long form. */
+static sShortUUID ShortenUUID(const AString & a_StringUUID)
+{
+ sShortUUID UUID;
+ switch (a_StringUUID.size())
+ {
+ case 32:
+ {
+ // Already a short UUID
+ std::memcpy(UUID.Data, a_StringUUID.data(), 32);
+ UUID.IsValid = true;
+ break;
+ }
+ case 36:
+ {
+ // Long UUID, confirm dashed
+ if (
+ (a_StringUUID[ 8] != '-') ||
+ (a_StringUUID[13] != '-') ||
+ (a_StringUUID[18] != '-') ||
+ (a_StringUUID[23] != '-')
+ )
+ {
+ break;
+ }
+
+ // Copy everying but the dashes from the string
+ std::memcpy(UUID.Data, a_StringUUID.data(), 8);
+ std::memcpy(UUID.Data + 8, a_StringUUID.data() + 9, 4);
+ std::memcpy(UUID.Data + 12, a_StringUUID.data() + 14, 4);
+ std::memcpy(UUID.Data + 16, a_StringUUID.data() + 19, 4);
+ std::memcpy(UUID.Data + 20, a_StringUUID.data() + 24, 12);
+ UUID.IsValid = true;
+ }
+ default: break;
+ }
+ return UUID;
+}
+
+
+
+
+
+/** Returns the integer value of the hex digit or 0xff if invalid. */
+static Byte FromHexDigit(char a_Hex)
+{
+ if (('0' <= a_Hex) && (a_Hex <= '9'))
+ {
+ return static_cast<Byte>(a_Hex - '0');
+ }
+ if (('a' <= a_Hex) && (a_Hex <= 'f'))
+ {
+ return static_cast<Byte>(a_Hex - 'a');
+ }
+ if (('A' <= a_Hex) && (a_Hex <= 'F'))
+ {
+ return static_cast<Byte>(a_Hex - 'A');
+ }
+ return 0xff;
+}
+
+
+
+
+
+/** From a number in the range [0, 16), returns the corresponding hex digit in lowercase. */
+static char ToHexDigit(UInt8 a_Nibble)
+{
+ ASSERT((a_Nibble & 0xf0) == 0);
+ return static_cast<char>(
+ (a_Nibble < 10) ?
+ ('0' + a_Nibble) :
+ ('a' + (a_Nibble - 10))
+ );
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// cUUID:
+
+bool cUUID::FromString(const AString & a_StringUUID)
+{
+ sShortUUID Norm = ShortenUUID(a_StringUUID);
+ if (!Norm.IsValid)
+ {
+ return false;
+ }
+
+ std::array<Byte, 16> ParsedUUID{{0}};
+ for (size_t i = 0; i != m_UUID.size(); ++i)
+ {
+ Byte HighNibble = FromHexDigit(Norm.Data[2 * i ]);
+ Byte LowNibble = FromHexDigit(Norm.Data[2 * i + 1]);
+ if ((HighNibble > 0x0f) || (LowNibble > 0x0f))
+ {
+ // Invalid hex digit
+ return false;
+ }
+
+ ParsedUUID[i] = static_cast<Byte>((HighNibble << 4) | LowNibble);
+ }
+
+ // Parsed successfully
+ m_UUID = ParsedUUID;
+ return true;
+}
+
+
+
+
+
+AString cUUID::ToShortString() const
+{
+ AString ShortString(32, '\0');
+ for (size_t i = 0; i != m_UUID.size(); ++i)
+ {
+ Byte HighNibble = (m_UUID[i] >> 4) & 0x0f;
+ Byte LowNibble = m_UUID[i] & 0x0f;
+
+ ShortString[2 * i ] = ToHexDigit(HighNibble);
+ ShortString[2 * i + 1] = ToHexDigit(LowNibble);
+ }
+ return ShortString;
+}
+
+
+
+
+
+AString cUUID::ToLongString() const
+{
+ AString LongString = ToShortString();
+ LongString.reserve(36);
+
+ // Convert to long form by inserting the dashes
+ auto First = LongString.begin();
+ LongString.insert(First + 8, '-');
+ LongString.insert(First + 13, '-');
+ LongString.insert(First + 18, '-');
+ LongString.insert(First + 23, '-');
+
+ return LongString;
+}
+
+
+
+
+
+UInt8 cUUID::Version() const
+{
+ return static_cast<UInt8>((m_UUID[6] >> 4) & 0x0f);
+}
+
+
+
+
+
+UInt8 cUUID::Variant() const
+{
+ const Byte VariantBits = static_cast<Byte>((m_UUID[9] >> 5) & 0x07);
+
+ /* Variant bits format:
+ bits | variant | Description
+ -----|---------|----------------------
+ 0xx | 0 | Obsolete
+ 10x | 1 | Standard UUID
+ 110 | 2 | Microsoft Legacy GUID
+ 111 | 3 | Reserved
+ */
+
+ if ((VariantBits & 0x04) == 0)
+ {
+ return 0;
+ }
+ else if ((VariantBits & 0x02) == 0)
+ {
+ return 1;
+ }
+ else if ((VariantBits & 0x01) == 0)
+ {
+ return 2;
+ }
+ else
+ {
+ return 3;
+ }
+}
+
+
+
+
+
+std::array<Byte, 16> cUUID::ToRaw() const
+{
+ std::array<Byte, 16> Raw(m_UUID);
+ if (Variant() == 2)
+ {
+ // Convert to microsoft mixed-endian format
+ // First 3 components are host-endian, last 2 are network
+ auto First = reinterpret_cast<UInt32 *>(Raw.data());
+ *First = ntohl(*First);
+
+ auto Second = reinterpret_cast<UInt16 *>(&Raw[4]);
+ *Second = ntohs(*Second);
+
+ auto Third = Second + 1;
+ *Third = ntohs(*Third);
+ }
+
+ return Raw;
+}
+
+
+
+
+
+void cUUID::FromRaw(const std::array<Byte, 16> & a_Raw)
+{
+ m_UUID = a_Raw;
+ if (Variant() != 2)
+ {
+ // Standard big-endian formats
+ return;
+ }
+
+ // Convert from microsoft mixed-endian format
+ // First 3 components are host-endian, last 2 are network
+ auto First = reinterpret_cast<UInt32 *>(m_UUID.data());
+ *First = htonl(*First);
+
+ auto Second = reinterpret_cast<UInt16 *>(&m_UUID[4]);
+ *Second = htons(*Second);
+
+ auto Third = Second + 1;
+ *Third = htons(*Third);
+}
+
+
+
+
+
+cUUID cUUID::GenerateVersion3(const AString & a_Name)
+{
+ cUUID UUID;
+ // Generate an md5 checksum, and use it as base for the ID:
+ const Byte * ByteString = reinterpret_cast<const Byte *>(a_Name.data());
+ md5(ByteString, a_Name.length(), UUID.m_UUID.data());
+
+ // Insert version number
+ UUID.m_UUID[6] = (UUID.m_UUID[6] & 0x0f) | 0x30;
+
+ /* Insert variant number
+ Note that by using 1000 instead of 10xx we are losing 2 bits
+ but this is needed for compatibility with the old string uuid generator */
+ UUID.m_UUID[8] = (UUID.m_UUID[8] & 0x0f) | 0x80;
+
+ return UUID;
+}
+
+
+
+
diff --git a/src/UUID.h b/src/UUID.h
new file mode 100644
index 000000000..12fef3e39
--- /dev/null
+++ b/src/UUID.h
@@ -0,0 +1,100 @@
+// UUID.h
+
+// Declares the cUUID class representing a Universally Unique Identifier
+
+#pragma once
+
+
+// tolua_begin
+
+class cUUID
+{
+public:
+ /** Default constructed "nil" UUID */
+ cUUID():
+ m_UUID()
+ {
+ }
+
+ /** Lexicographically compare bytes with another UUID.
+ Returns:
+ 0 when equal to a_Other,
+ < 0 when less than a_Other,
+ > 0 when greater than a_Other */
+ int Compare(const cUUID & a_Other) const
+ {
+ return std::memcmp(m_UUID.data(), a_Other.m_UUID.data(), m_UUID.size());
+ }
+
+ /** Returns true if this contains the "nil" UUID with all bits set to 0 */
+ bool IsNil() const
+ {
+ return (m_UUID == std::array<Byte, 16>{{0}});
+ }
+
+ /** Tries to interpret the string as a short or long form UUID and assign from it.
+ On error, returns false and does not set the value. */
+ bool FromString(const AString & a_StringUUID);
+
+ /** Converts the UUID to a short form string (i.e without dashes). */
+ AString ToShortString() const;
+
+ /** Converts the UUID to a long form string (i.e. with dashes). */
+ AString ToLongString() const;
+
+ /** Returns the version number of the UUID. */
+ UInt8 Version() const;
+
+ /** Returns the variant number of the UUID. */
+ UInt8 Variant() const;
+
+ /** Generates a version 3, variant 1 UUID based on the md5 hash of a_Name. */
+ static cUUID GenerateVersion3(const AString & a_Name);
+
+ // tolua_end
+
+ /** Converts UUID to raw memory representation, respecting UUID variant. */
+ std::array<Byte, 16> ToRaw() const;
+
+ /** Assigns from raw memory representation, respecting UUID variant. */
+ void FromRaw(const std::array<Byte, 16> & a_Raw);
+
+private:
+ /** Binary UUID stored big-endian. */
+ std::array<Byte, 16> m_UUID;
+}; // tolua_export
+
+
+// Comparison operators:
+
+inline bool operator == (const cUUID & a_Lhs, const cUUID & a_Rhs)
+{
+ return (a_Lhs.Compare(a_Rhs) == 0);
+}
+
+inline bool operator != (const cUUID & a_Lhs, const cUUID & a_Rhs)
+{
+ return (a_Lhs.Compare(a_Rhs) != 0);
+}
+
+inline bool operator < (const cUUID & a_Lhs, const cUUID & a_Rhs)
+{
+ return (a_Lhs.Compare(a_Rhs) < 0);
+}
+
+inline bool operator <= (const cUUID & a_Lhs, const cUUID & a_Rhs)
+{
+ return (a_Lhs.Compare(a_Rhs) <= 0);
+}
+
+inline bool operator > (const cUUID & a_Lhs, const cUUID & a_Rhs)
+{
+ return (a_Lhs.Compare(a_Rhs) > 0);
+}
+
+inline bool operator >= (const cUUID & a_Lhs, const cUUID & a_Rhs)
+{
+ return (a_Lhs.Compare(a_Rhs) >= 0);
+}
+
+
diff --git a/src/World.cpp b/src/World.cpp
index 8d8ba90a5..04ca1709e 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -10,6 +10,7 @@
#include "SetChunkData.h"
#include "DeadlockDetect.h"
#include "LineBlockTracer.h"
+#include "UUID.h"
// Serializers
#include "WorldStorage/ScoreboardSerializer.h"
@@ -3241,7 +3242,7 @@ bool cWorld::FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCa
-bool cWorld::DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallback & a_Callback)
+bool cWorld::DoWithPlayerByUUID(const cUUID & a_PlayerUUID, cPlayerListCallback & a_Callback)
{
return DoWithPlayerByUUID(a_PlayerUUID, std::bind(&cPlayerListCallback::Item, &a_Callback, std::placeholders::_1));
}
@@ -3250,7 +3251,7 @@ bool cWorld::DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallbac
-bool cWorld::DoWithPlayerByUUID(const AString & a_PlayerUUID, cLambdaPlayerCallback a_Callback)
+bool cWorld::DoWithPlayerByUUID(const cUUID & a_PlayerUUID, cLambdaPlayerCallback a_Callback)
{
cCSLock Lock(m_CSPlayers);
for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
diff --git a/src/World.h b/src/World.h
index 451462582..cbaf9cb95 100644
--- a/src/World.h
+++ b/src/World.h
@@ -50,6 +50,7 @@ class cCompositeChat;
class cSetChunkData;
class cBroadcaster;
class cDeadlockDetect;
+class cUUID;
typedef std::list< cPlayer * > cPlayerList;
typedef std::list< std::pair< std::unique_ptr<cPlayer>, cWorld * > > cAwaitingPlayerList;
@@ -287,8 +288,8 @@ public:
cPlayer * FindClosestPlayer(Vector3d a_Pos, float a_SightLimit, bool a_CheckLineOfSight = true);
/** Finds the player over his uuid and calls the callback */
- bool DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
- bool DoWithPlayerByUUID(const AString & a_PlayerUUID, cLambdaPlayerCallback a_Callback); // Lambda version
+ bool DoWithPlayerByUUID(const cUUID & a_PlayerUUID, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
+ bool DoWithPlayerByUUID(const cUUID & a_PlayerUUID, cLambdaPlayerCallback a_Callback); // Lambda version
void SendPlayerList(cPlayer * a_DestPlayer); // Sends playerlist to the player
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index 8c60aac0d..73c633e1a 100644
--- a/src/WorldStorage/NBTChunkSerializer.cpp
+++ b/src/WorldStorage/NBTChunkSerializer.cpp
@@ -7,6 +7,7 @@
#include "EnchantmentSerializer.h"
#include "../ItemGrid.h"
#include "../StringCompression.h"
+#include "../UUID.h"
#include "FastNBT.h"
#include "../BlockEntities/BeaconEntity.h"
@@ -382,7 +383,7 @@ void cNBTChunkSerializer::AddMobHeadEntity(cMobHeadEntity * a_MobHead)
// The new Block Entity format for a Mob Head. See: https://minecraft.gamepedia.com/Head#Block_entity
m_Writer.BeginCompound("Owner");
- m_Writer.AddString("Id", a_MobHead->GetOwnerUUID());
+ m_Writer.AddString("Id", a_MobHead->GetOwnerUUID().ToShortString());
m_Writer.AddString("Name", a_MobHead->GetOwnerName());
m_Writer.BeginCompound("Properties");
m_Writer.BeginList("textures", TAG_Compound);
@@ -679,9 +680,9 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster)
{
m_Writer.AddString("Owner", Wolf->GetOwnerName());
}
- if (!Wolf->GetOwnerUUID().empty())
+ if (!Wolf->GetOwnerUUID().IsNil())
{
- m_Writer.AddString("OwnerUUID", Wolf->GetOwnerUUID());
+ m_Writer.AddString("OwnerUUID", Wolf->GetOwnerUUID().ToShortString());
}
m_Writer.AddByte("Sitting", Wolf->IsSitting() ? 1 : 0);
m_Writer.AddByte("Angry", Wolf->IsAngry() ? 1 : 0);
@@ -709,9 +710,9 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster)
{
m_Writer.AddString("Owner", Ocelot->GetOwnerName());
}
- if (!Ocelot->GetOwnerUUID().empty())
+ if (!Ocelot->GetOwnerUUID().IsNil())
{
- m_Writer.AddString("OwnerUUID", Ocelot->GetOwnerUUID());
+ m_Writer.AddString("OwnerUUID", Ocelot->GetOwnerUUID().ToShortString());
}
m_Writer.AddByte("Sitting", Ocelot->IsSitting() ? 1 : 0);
m_Writer.AddInt ("CatType", Ocelot->GetOcelotType());
diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp
index 7aa3eb0cd..bbbffb07f 100755
--- a/src/WorldStorage/WSSAnvil.cpp
+++ b/src/WorldStorage/WSSAnvil.cpp
@@ -1398,12 +1398,13 @@ cBlockEntity * cWSSAnvil::LoadMobHeadFromNBT(const cParsedNBT & a_NBT, int a_Tag
int ownerLine = a_NBT.FindChildByName(a_TagIdx, "Owner");
if (ownerLine >= 0)
{
- AString OwnerName, OwnerUUID, OwnerTexture, OwnerTextureSignature;
+ AString OwnerName, OwnerTexture, OwnerTextureSignature;
+ cUUID OwnerUUID;
currentLine = a_NBT.FindChildByName(ownerLine, "Id");
if (currentLine >= 0)
{
- OwnerUUID = a_NBT.GetString(currentLine);
+ OwnerUUID.FromString(a_NBT.GetString(currentLine));
}
currentLine = a_NBT.FindChildByName(ownerLine, "Name");
@@ -2526,7 +2527,7 @@ void cWSSAnvil::LoadOcelotFromNBT(cEntityList & a_Entities, const cParsedNBT & a
}
auto OwnerInfo = LoadEntityOwner(a_NBT, a_TagIdx);
- if (!OwnerInfo.first.empty() && !OwnerInfo.second.empty())
+ if (!OwnerInfo.first.empty() && !OwnerInfo.second.IsNil())
{
Monster->SetOwner(OwnerInfo.first, OwnerInfo.second);
Monster->SetIsTame(true);
@@ -2927,7 +2928,7 @@ void cWSSAnvil::LoadWolfFromNBT(cEntityList & a_Entities, const cParsedNBT & a_N
}
auto OwnerInfo = LoadEntityOwner(a_NBT, a_TagIdx);
- if (!OwnerInfo.first.empty() && !OwnerInfo.second.empty())
+ if (!OwnerInfo.first.empty() && !OwnerInfo.second.IsNil())
{
Monster->SetOwner(OwnerInfo.first, OwnerInfo.second);
Monster->SetIsTame(true);
@@ -3064,43 +3065,39 @@ void cWSSAnvil::LoadPigZombieFromNBT(cEntityList & a_Entities, const cParsedNBT
-std::pair<AString, AString> cWSSAnvil::LoadEntityOwner(const cParsedNBT & a_NBT, int a_TagIdx)
+std::pair<AString, cUUID> cWSSAnvil::LoadEntityOwner(const cParsedNBT & a_NBT, int a_TagIdx)
{
// Load the owner information. OwnerUUID or Owner may be specified, possibly both:
- AString OwnerUUID, OwnerName;
+ AString OwnerName;
+ cUUID OwnerUUID;
int OwnerUUIDIdx = a_NBT.FindChildByName(a_TagIdx, "OwnerUUID");
if (OwnerUUIDIdx > 0)
{
- OwnerUUID = a_NBT.GetString(OwnerUUIDIdx);
+ OwnerUUID.FromString(a_NBT.GetString(OwnerUUIDIdx));
}
int OwnerIdx = a_NBT.FindChildByName(a_TagIdx, "Owner");
if (OwnerIdx > 0)
{
OwnerName = a_NBT.GetString(OwnerIdx);
}
- if (OwnerName.empty() && OwnerUUID.empty())
+ if (OwnerName.empty() && OwnerUUID.IsNil())
{
// There is no owner, bail out:
- return std::pair<AString, AString>();
+ return {};
}
// Convert name to UUID, if needed:
- if (OwnerUUID.empty())
+ if (OwnerUUID.IsNil())
{
// This entity has only playername stored (pre-1.7.6), look up the UUID
// The lookup is blocking, but we're running in a separate thread, so it's ok
OwnerUUID = cRoot::Get()->GetMojangAPI().GetUUIDFromPlayerName(OwnerName);
- if (OwnerUUID.empty())
+ if (OwnerUUID.IsNil())
{
// Not a known player, un-tame the entity by bailing out
- return std::pair<AString, AString>();
+ return {};
}
}
- else
- {
- // Normalize the UUID:
- OwnerUUID = cMojangAPI::MakeUUIDShort(OwnerUUID);
- }
// Convert UUID to name, if needed:
if (OwnerName.empty())
@@ -3110,11 +3107,11 @@ std::pair<AString, AString> cWSSAnvil::LoadEntityOwner(const cParsedNBT & a_NBT,
if (OwnerName.empty())
{
// Not a known player, un-tame the entity by bailing out
- return std::pair<AString, AString>();
+ return {};
}
}
- return std::make_pair(OwnerName, OwnerUUID);
+ return { OwnerName, OwnerUUID };
}
diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h
index a53d8d8c4..0f32d1a2e 100755
--- a/src/WorldStorage/WSSAnvil.h
+++ b/src/WorldStorage/WSSAnvil.h
@@ -20,6 +20,7 @@ class cItemGrid;
class cMonster;
class cProjectileEntity;
class cHangingEntity;
+class cUUID;
@@ -230,8 +231,8 @@ protected:
void LoadPigZombieFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
/** Loads the owner name and UUID from the entity at the specified NBT tag.
- Returns a pair of {name, uuid}. If the entity is not owned, both are empty strings. */
- std::pair<AString, AString> LoadEntityOwner(const cParsedNBT & a_NBT, int a_TagIdx);
+ Returns a pair of {name, uuid}. If the entity is not owned, name is an empty string and uuid is nil. */
+ std::pair<AString, cUUID> LoadEntityOwner(const cParsedNBT & a_NBT, int a_TagIdx);
/** Loads entity common data from the NBT compound; returns true if successful */
bool LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx);