1
0
Fork 0

Add cUUID class (#3871)

This commit is contained in:
peterbell10 2017-08-25 13:43:18 +01:00 committed by Alexander Harkness
parent 86d52c3e17
commit f4f2fc7c3d
54 changed files with 1339 additions and 508 deletions

View File

@ -1463,7 +1463,7 @@ end
{
{
Name = "UUID",
Type = "string",
Type = "cUUID",
},
},
Returns =
@ -1472,7 +1472,7 @@ end
Type = "boolean",
},
},
Notes = "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.",
Notes = "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).",
},
Kick =
{
@ -8485,10 +8485,9 @@ a_Player:OpenWindow(Window);
<p>
All the functions are static, call them using the <code>cMojangAPI:Function()</code> convention.</p>
<p>
Mojang uses two formats for UUIDs, short and dashed. Cuberite works with short UUIDs internally, but
will convert to dashed UUIDs where needed - in the protocol login for example. The MakeUUIDShort()
and MakeUUIDDashed() functions are provided for plugins to use for conversion between the two
formats.</p>
Mojang uses two formats for UUIDs, short and dashed. Cuberite will accept either format for any
functions taking a UUID. The MakeUUIDShort() and MakeUUIDDashed() functions are provided for plugins
to use for conversion between the two formats.</p>
<p>
This class will cache values returned by the API service. The cache will hold the values for 7 days
by default, after that, they will no longer be available. This is in order to not let the server get
@ -8509,10 +8508,10 @@ a_Player:OpenWindow(Window);
},
{
Name = "UUID",
Type = "string",
Type = "cUUID",
},
},
Notes = "Adds the specified PlayerName-to-UUID mapping into the cache, with current timestamp. Accepts both short or dashed UUIDs. ",
Notes = "Adds the specified PlayerName-to-UUID mapping into the cache, with current timestamp.",
},
GetPlayerNameFromUUID =
{
@ -8521,7 +8520,7 @@ a_Player:OpenWindow(Window);
{
{
Name = "UUID",
Type = "string",
Type = "cUUID",
},
{
Name = "UseOnlyCached",
@ -8592,7 +8591,7 @@ a_Player:OpenWindow(Window);
{
{
Name = "UUID",
Type = "string",
Type = "cUUID",
},
},
Returns =
@ -8602,7 +8601,7 @@ a_Player:OpenWindow(Window);
Type = "string",
},
},
Notes = "Converts the UUID to a dashed format (\"01234567-8901-2345-6789-012345678901\"). Accepts both dashed or short UUIDs. Logs a warning and returns an empty string if UUID format not recognized.",
Notes = "Converts the UUID to a dashed format (\"01234567-8901-2345-6789-012345678901\"). An alias for cUUID:ToLongString()",
},
MakeUUIDShort =
{
@ -8611,7 +8610,7 @@ a_Player:OpenWindow(Window);
{
{
Name = "UUID",
Type = "string",
Type = "cUUID",
},
},
Returns =
@ -8621,7 +8620,7 @@ a_Player:OpenWindow(Window);
Type = "string",
},
},
Notes = "Converts the UUID to a short format (without dashes, \"01234567890123456789012345678901\"). Accepts both dashed or short UUIDs. Logs a warning and returns an empty string if UUID format not recognized.",
Notes = "Converts the UUID to a short format (without dashes, \"01234567890123456789012345678901\"). An alias for cUUID:ToShortString()",
},
},
},
@ -11181,7 +11180,7 @@ a_Player:OpenWindow(Window);
{
{
Name = "PlayerUUID",
Type = "string",
Type = "cUUID",
},
{
Name = "CallbackFunction",
@ -12441,6 +12440,135 @@ end
},
},
},
cUUID =
{
Desc = [[
Class representing a Universally Unique Identifier.
Note that all Cuberite's API functions that take a cUUID parameter will also
accept a string in its place, as long as that string can be converted to a cUUID
(using the {{#FromString_1|cUUID:FromString}} function).
]],
Functions =
{
constructor =
{
Returns =
{
{
Type = "cUUID",
},
},
Notes = "Constructs a nil-valued UUID (all zeros)",
},
Compare =
{
Params =
{
{
Name = "Other",
Type = "cUUID",
},
},
Returns =
{
{
Type = "number",
},
},
Notes = [[
Compares this UUID with the specified Other UUID, Returns:
0 when equal to Other,
< 0 when less than Other,
> 0 when greater than Other
]],
},
IsNil =
{
Returns =
{
{
Type = "boolean",
},
},
Notes = "Returns true if this contains the \"nil\" UUID with all bits set to 0",
},
FromString =
{
Params =
{
{
Name = "StringUUID",
Type = "string",
},
},
Returns =
{
{
Type = "boolean",
},
},
Notes = "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.",
},
ToShortString =
{
Returns =
{
{
Type = "string",
},
},
Notes = "Converts the UUID to a short form string (i.e without dashes).",
},
ToLongString =
{
Returns =
{
{
Type = "string",
},
},
Notes = "Converts the UUID to a long form string (i.e with dashes).",
},
Version =
{
Returns =
{
{
Type = "number",
},
},
Notes = "Returns the version number of the UUID.",
},
Variant =
{
Returns =
{
{
Type = "number",
},
},
Notes = "Returns the variant number of the UUID",
},
GenerateVersion3 =
{
IsStatic = true,
Params =
{
{
Name = "Name",
Type = "string",
},
},
Returns =
{
{
Type = "cUUID",
},
},
Notes = "Generates a version 3, variant 1 UUID based on the md5 hash of Name."
},
},
},
cWebPlugin =
{
Desc = "",

View File

@ -258,7 +258,7 @@ return
{
{
Name = "PlayerUUID",
Type = "string",
Type = "cUUID",
},
},
Returns =
@ -276,7 +276,7 @@ return
{
{
Name = "PlayerUUID",
Type = "string",
Type = "cUUID",
},
},
Returns =
@ -303,7 +303,7 @@ return
{
{
Name = "PlayerUUID",
Type = "string",
Type = "cUUID",
},
},
Returns =
@ -322,7 +322,7 @@ return
{
{
Name = "PlayerUUID",
Type = "string",
Type = "cUUID",
},
},
Returns =
@ -340,7 +340,7 @@ return
{
{
Name = "PlayerUUID",
Type = "string",
Type = "cUUID",
},
},
Returns =
@ -502,7 +502,7 @@ return
{
{
Name = "PlayerUUID",
Type = "string",
Type = "cUUID",
},
},
Returns =
@ -604,7 +604,7 @@ return
{
{
Name = "PlayerUUID",
Type = "string",
Type = "cUUID",
},
},
Notes = "Removes the player's rank; the player's 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.",
@ -699,7 +699,7 @@ return
{
{
Name = "PlayerUUID",
Type = "string",
Type = "cUUID",
},
{
Name = "PlayerName",

View File

@ -18,7 +18,7 @@ return
Each world runs several separate threads used for various housekeeping purposes, the most important
of those is the Tick thread. This thread updates the game logic 20 times per second, and it is
the thread where all the gameplay actions are evaluated. Liquid physics, entity interactions,
player ovement etc., all are applied in this thread.</p>
player movement etc., all are applied in this thread.</p>
<p>
Additional threads include the generation thread (generates new chunks as needed, storage thread
(saves and loads chunk from the disk), lighting thread (updates block light values) and the
@ -901,7 +901,7 @@ function OnAllChunksAvailable()</pre> All return values from the callbacks are i
{
{
Name = "PlayerUUID",
Type = "string",
Type = "cUUID",
},
{
Name = "CallbackFunction",

View File

@ -29,6 +29,7 @@ set_exe_flags()
set(SHARED_SRC
../../src/ByteBuffer.cpp
../../src/StringUtils.cpp
../../src/UUID.cpp
../../src/PolarSSL++/AesCfb128Decryptor.cpp
../../src/PolarSSL++/AesCfb128Encryptor.cpp
../../src/PolarSSL++/CryptoKey.cpp
@ -41,6 +42,7 @@ set(SHARED_SRC
set(SHARED_HDR
../../src/ByteBuffer.h
../../src/StringUtils.h
../../src/UUID.h
../../src/PolarSSL++/AesCfb128Decryptor.h
../../src/PolarSSL++/AesCfb128Encryptor.h
../../src/PolarSSL++/CryptoKey.h

View File

@ -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"

View File

@ -139,6 +139,7 @@ set(BINDING_DEPENDENCIES
../StringUtils.h
../Tracer.h
../UI/Window.h
../UUID.h
../Vector3.h
../WebAdmin.h
../World.h

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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:

View File

@ -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>);

View File

@ -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)
{

View File

@ -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

View File

@ -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;
}

View File

@ -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)

View File

@ -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

View File

@ -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)
{

View File

@ -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;

View File

@ -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);

View File

@ -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:

View File

@ -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;
} ;

View File

@ -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()) ||

View File

@ -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;
} ;

View File

@ -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);

View File

@ -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);
};

View File

@ -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);
}
}
}

View File

@ -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);

View File

@ -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)
for (auto val : a_UUID.ToRaw())
{
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)
{
auto val = static_cast<UInt8>(HexDigitValue(a_UUID[i]) << 4 | HexDigitValue(a_UUID[i + 1]));
VERIFY(m_Out.WriteBEUInt8(val));
}
}

View File

@ -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; }

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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:

View File

@ -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)
{

View File

@ -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);

View File

@ -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);

View File

@ -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

283
src/UUID.cpp Normal file
View File

@ -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;
}

100
src/UUID.h Normal file
View File

@ -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);
}

View File

@ -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)

View File

@ -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

View File

@ -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());

View File

@ -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 };
}

View File

@ -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);

View File

@ -19,6 +19,7 @@ set (SHARED_HDRS
set (SRCS
ByteBufferTest.cpp
Stubs.cpp
)
source_group("Shared" FILES ${SHARED_SRCS} ${SHARED_HDRS})

View File

@ -0,0 +1,16 @@
// Stubs.cpp
// Implements stubs of various Cuberite methods that are needed for linking but not for runtime
// This is required so that we don't bring in the entire Cuberite via dependencies
#include "Globals.h"
#include "UUID.h"
void cUUID::FromRaw(const std::array<Byte, 16> &){}

View File

@ -2,3 +2,8 @@
// LuaState_Declaration.inc
// Dummy include file needed for LuaState to compile successfully
bool GetStackValue(int, cUUID *&);

View File

@ -14,6 +14,7 @@ class cPluginLua;
class cBoundingBox;
template <typename T> class cItemCallback;
class cEntity;
class cUUID;

View File

@ -6,9 +6,11 @@
#include "Globals.h"
#include "BlockInfo.h"
#include "UUID.h"
#include "Bindings.h"
#include "Bindings/DeprecatedBindings.h"
#include "Bindings/LuaJson.h"
#include "Bindings/LuaState.h"
#include "Bindings/ManualBindings.h"
#include "BlockEntities/BlockEntity.h"
#include "Blocks/BlockHandler.h"
@ -332,3 +334,21 @@ cBlockEntity * cBlockEntity::Clone(int a_BlockX, int a_BlockY, int a_BlockZ)
bool cLuaState::GetStackValue(int, cUUID *&)
{
return false;
}
bool cUUID::FromString(const AString&)
{
return false;
}

View File

@ -2,3 +2,8 @@
// LuaState_Declaration.inc
// Dummy include file needed for LuaState to compile successfully
bool GetStackValue(int, cUUID *&);

View File

@ -14,6 +14,7 @@ class cPluginLua;
class cBoundingBox;
template <typename T> class cItemCallback;
class cEntity;
class cUUID;

View File

@ -7,13 +7,14 @@
#include "Globals.h"
#include "BlockInfo.h"
#include "Bindings.h"
#include "DeadlockDetect.h"
#include "UUID.h"
#include "Bindings/DeprecatedBindings.h"
#include "Bindings/LuaJson.h"
#include "Bindings/ManualBindings.h"
#include "BlockEntities/BlockEntity.h"
#include "Blocks/BlockHandler.h"
#include "Generating/ChunkDesc.h"
#include "DeadlockDetect.h"
@ -333,3 +334,21 @@ cBlockEntity * cBlockEntity::Clone(int a_BlockX, int a_BlockY, int a_BlockZ)
bool cLuaState::GetStackValue(int, cUUID *&)
{
return false;
}
bool cUUID::FromString(const AString &)
{
return true;
}