1
0

Player data loading cleanup

* Kick player if data were corrupt to avoid making it worse
This commit is contained in:
Tiger Wang 2021-03-28 22:34:54 +01:00
parent 222d9957a1
commit 8a30a4a7b8
6 changed files with 106 additions and 210 deletions

View File

@ -140,15 +140,6 @@ void cClientHandle::Destroy(void)
void cClientHandle::GenerateOfflineUUID(void)
{
m_UUID = GenerateOfflineUUID(m_Username);
}
AString cClientHandle::FormatChatPrefix( AString cClientHandle::FormatChatPrefix(
bool ShouldAppendChatPrefixes, const AString & a_ChatPrefixS, bool ShouldAppendChatPrefixes, const AString & a_ChatPrefixS,
const AString & m_Color1, const AString & m_Color2 const AString & m_Color1, const AString & m_Color2
@ -318,7 +309,19 @@ void cClientHandle::Authenticate(const AString & a_Name, const cUUID & a_UUID, c
void cClientHandle::FinishAuthenticate(const AString & a_Name, const cUUID & a_UUID, const Json::Value & a_Properties) void cClientHandle::FinishAuthenticate(const AString & a_Name, const cUUID & a_UUID, const Json::Value & a_Properties)
{ {
// Serverside spawned player (so data are loaded). // Serverside spawned player (so data are loaded).
auto Player = std::make_unique<cPlayer>(shared_from_this()); std::unique_ptr<cPlayer> Player;
try
{
Player = std::make_unique<cPlayer>(shared_from_this());
}
catch (const std::exception & Oops)
{
LOGWARNING("Error reading player \"%s\": %s", GetUsername().c_str(), Oops.what());
Kick("Contact an operator.\n\nYour player's save files could not be parsed.\nTo avoid data loss you are prevented from joining.");
return;
}
m_Player = Player.get(); m_Player = Player.get();
/* /*
@ -1461,9 +1464,7 @@ void cClientHandle::HandleChat(const AString & a_Message)
{ {
if ((a_Message.size()) > MAX_CHAT_MSG_LENGTH) if ((a_Message.size()) > MAX_CHAT_MSG_LENGTH)
{ {
this->Kick(std::string("Please don't exceed the maximum message length of ") Kick("Please don't exceed the maximum message length of " + std::to_string(MAX_CHAT_MSG_LENGTH));
+ std::to_string(MAX_CHAT_MSG_LENGTH)
);
return; return;
} }
// We no longer need to postpone message processing, because the messages already arrive in the Tick thread // We no longer need to postpone message processing, because the messages already arrive in the Tick thread

View File

@ -90,12 +90,6 @@ public: // tolua_export
and the results are passed to MCS running in offline mode. */ and the results are passed to MCS running in offline mode. */
void SetProperties(const Json::Value & a_Properties) { m_Properties = a_Properties; } void SetProperties(const Json::Value & a_Properties) { m_Properties = a_Properties; }
/** Generates an UUID based on the username stored for this client, and stores it in the m_UUID member.
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.
Internally calls the GenerateOfflineUUID static function. */
void GenerateOfflineUUID(void);
/** Generates an UUID based on the player name provided. /** Generates an UUID based on the player name provided.
This is used for the offline (non-auth) mode, when there's no UUID source. 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. */ Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same. */

View File

@ -37,23 +37,6 @@
namespace namespace
{ {
/** Returns the old Offline UUID generated before becoming vanilla compliant. */
cUUID GetOldStyleOfflineUUID(const AString & a_PlayerName)
{
// Use lowercase username
auto BaseUUID = cUUID::GenerateVersion3(StrToLower(a_PlayerName)).ToRaw();
// Clobber a full nibble around the variant bits
BaseUUID[8] = (BaseUUID[8] & 0x0f) | 0x80;
cUUID Ret;
Ret.FromRaw(BaseUUID);
return Ret;
}
/** Returns the folder for the player data based on the UUID given. /** Returns the folder for the player data based on the UUID given.
This can be used both for online and offline UUIDs. */ This can be used both for online and offline UUIDs. */
AString GetUUIDFolderName(const cUUID & a_Uuid) AString GetUUIDFolderName(const cUUID & a_Uuid)
@ -115,7 +98,6 @@ cPlayer::cPlayer(const std::shared_ptr<cClientHandle> & a_Client) :
m_bIsInBed(false), m_bIsInBed(false),
m_TicksUntilNextSave(PLAYER_INVENTORY_SAVE_INTERVAL), m_TicksUntilNextSave(PLAYER_INVENTORY_SAVE_INTERVAL),
m_bIsTeleporting(false), m_bIsTeleporting(false),
m_UUID((a_Client != nullptr) ? a_Client->GetUUID() : cUUID{}),
m_SkinParts(0), m_SkinParts(0),
m_MainHand(mhRight) m_MainHand(mhRight)
{ {
@ -129,22 +111,7 @@ cPlayer::cPlayer(const std::shared_ptr<cClientHandle> & a_Client) :
m_Health = MAX_HEALTH; m_Health = MAX_HEALTH;
cWorld * World = nullptr; cWorld * World = nullptr;
if (!LoadFromDisk(World)) LoadFromDisk(World);
{
m_Inventory.Clear();
SetPosX(World->GetSpawnX());
SetPosY(World->GetSpawnY());
SetPosZ(World->GetSpawnZ());
// This is a new player. Set the player spawn point to the spawn point of the default world
SetBedPos(Vector3i(static_cast<int>(World->GetSpawnX()), static_cast<int>(World->GetSpawnY()), static_cast<int>(World->GetSpawnZ())), World);
m_EnchantmentSeed = GetRandomProvider().RandInt<unsigned int>(); // Use a random number to seed the enchantment generator
FLOGD("Player \"{0}\" is connecting for the first time, spawning at default world spawn {1:.2f}",
GetName(), GetPosition()
);
}
m_LastGroundHeight = static_cast<float>(GetPosY()); m_LastGroundHeight = static_cast<float>(GetPosY());
m_Stance = GetPosY() + 1.62; m_Stance = GetPosY() + 1.62;
@ -1734,70 +1701,30 @@ void cPlayer::TossPickup(const cItem & a_Item)
bool cPlayer::LoadFromDisk(cWorldPtr & a_World) void cPlayer::LoadFromDisk(cWorldPtr & a_World)
{ {
LoadRank(); LoadRank();
const auto & UUID = GetUUID();
// Load from the UUID file: // Load from the UUID file:
if (LoadFromFile(GetUUIDFileName(m_UUID), a_World)) if (LoadFromFile(GetUUIDFileName(UUID), a_World))
{ {
return true; return;
} }
// Check for old offline UUID filename, if it exists migrate to new filename // Player not found:
cUUID OfflineUUID = cClientHandle::GenerateOfflineUUID(GetName()); a_World = cRoot::Get()->GetDefaultWorld();
auto OldFilename = GetUUIDFileName(GetOldStyleOfflineUUID(GetName())); LOG("Player \"%s\" (%s) data not found, resetting to defaults", GetName().c_str(), UUID.ToShortString().c_str());
auto NewFilename = GetUUIDFileName(m_UUID);
// Only move if there isn't already a new file
if (!cFile::IsFile(NewFilename) && cFile::IsFile(OldFilename))
{
cFile::CreateFolderRecursive(GetUUIDFolderName(m_UUID)); // Ensure folder exists to move to
if (
cFile::Rename(OldFilename, NewFilename) &&
(m_UUID == OfflineUUID) &&
LoadFromFile(NewFilename, a_World)
)
{
return true;
}
}
// Load from the offline UUID file, if allowed: const Vector3i WorldSpawn(static_cast<int>(a_World->GetSpawnX()), static_cast<int>(a_World->GetSpawnY()), static_cast<int>(a_World->GetSpawnZ()));
const char * OfflineUsage = " (unused)"; SetPosition(WorldSpawn);
if (cRoot::Get()->GetServer()->ShouldLoadOfflinePlayerData()) SetBedPos(WorldSpawn, a_World);
{
OfflineUsage = "";
if (LoadFromFile(GetUUIDFileName(OfflineUUID), a_World))
{
return true;
}
}
// Load from the old-style name-based file, if allowed: m_Inventory.Clear();
if (cRoot::Get()->GetServer()->ShouldLoadNamedPlayerData()) m_EnchantmentSeed = GetRandomProvider().RandInt<unsigned int>(); // Use a random number to seed the enchantment generator
{
AString OldStyleFileName = Printf("players/%s.json", GetName().c_str());
if (LoadFromFile(OldStyleFileName, a_World))
{
// Save in new format and remove the old file
if (SaveToDisk())
{
cFile::Delete(OldStyleFileName);
}
return true;
}
}
// None of the files loaded successfully FLOGD("Player \"{0}\" is connecting for the first time, spawning at default world spawn {1:.2f}", GetName(), GetPosition());
LOG("Player data file not found for %s (%s, offline %s%s), will be reset to defaults.",
GetName().c_str(), m_UUID.ToShortString().c_str(), OfflineUUID.ToShortString().c_str(), OfflineUsage
);
if (a_World == nullptr)
{
a_World = cRoot::Get()->GetDefaultWorld();
}
return false;
} }
@ -1806,35 +1733,31 @@ bool cPlayer::LoadFromDisk(cWorldPtr & a_World)
bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World) bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World)
{ {
// Load the data from the file: Json::Value Root;
cFile f;
if (!f.Open(a_FileName, cFile::fmRead))
{
// This is a new player whom we haven't seen yet, bail out, let them have the defaults
return false;
}
AString buffer;
if (f.ReadRestOfFile(buffer) != f.GetSize())
{
LOGWARNING("Cannot read player data from file \"%s\"", a_FileName.c_str());
return false;
}
f.Close();
// Parse the JSON format: try
Json::Value root;
AString ParseError;
if (!JsonUtils::ParseString(buffer, root, &ParseError))
{ {
FLOGWARNING( // Load the data from the file and parse:
"Cannot parse player data in file \"{0}\":\n {1}", InputFileStream(a_FileName) >> Root;
a_FileName, ParseError }
); catch (const Json::Exception & Oops)
return false; {
// Parse failure:
throw std::runtime_error(Oops.what());
}
catch (const InputFileStream::failure &)
{
if (errno == ENOENT)
{
// This is a new player whom we haven't seen yet, bail out, let them have the defaults:
return false;
}
throw;
} }
// Load the player data: // Load the player data:
Json::Value & JSON_PlayerPosition = root["position"]; Json::Value & JSON_PlayerPosition = Root["position"];
if (JSON_PlayerPosition.size() == 3) if (JSON_PlayerPosition.size() == 3)
{ {
SetPosX(JSON_PlayerPosition[0].asDouble()); SetPosX(JSON_PlayerPosition[0].asDouble());
@ -1843,7 +1766,7 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World)
m_LastPosition = GetPosition(); m_LastPosition = GetPosition();
} }
Json::Value & JSON_PlayerRotation = root["rotation"]; Json::Value & JSON_PlayerRotation = Root["rotation"];
if (JSON_PlayerRotation.size() == 3) if (JSON_PlayerRotation.size() == 3)
{ {
SetYaw (static_cast<float>(JSON_PlayerRotation[0].asDouble())); SetYaw (static_cast<float>(JSON_PlayerRotation[0].asDouble()));
@ -1851,18 +1774,18 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World)
SetRoll (static_cast<float>(JSON_PlayerRotation[2].asDouble())); SetRoll (static_cast<float>(JSON_PlayerRotation[2].asDouble()));
} }
m_Health = root.get("health", 0).asFloat(); m_Health = Root.get("health", 0).asFloat();
m_AirLevel = root.get("air", MAX_AIR_LEVEL).asInt(); m_AirLevel = Root.get("air", MAX_AIR_LEVEL).asInt();
m_FoodLevel = root.get("food", MAX_FOOD_LEVEL).asInt(); m_FoodLevel = Root.get("food", MAX_FOOD_LEVEL).asInt();
m_FoodSaturationLevel = root.get("foodSaturation", MAX_FOOD_LEVEL).asDouble(); m_FoodSaturationLevel = Root.get("foodSaturation", MAX_FOOD_LEVEL).asDouble();
m_FoodTickTimer = root.get("foodTickTimer", 0).asInt(); m_FoodTickTimer = Root.get("foodTickTimer", 0).asInt();
m_FoodExhaustionLevel = root.get("foodExhaustion", 0).asDouble(); m_FoodExhaustionLevel = Root.get("foodExhaustion", 0).asDouble();
m_LifetimeTotalXp = root.get("xpTotal", 0).asInt(); m_LifetimeTotalXp = Root.get("xpTotal", 0).asInt();
m_CurrentXp = root.get("xpCurrent", 0).asInt(); m_CurrentXp = Root.get("xpCurrent", 0).asInt();
m_IsFlying = root.get("isflying", 0).asBool(); m_IsFlying = Root.get("isflying", 0).asBool();
m_EnchantmentSeed = root.get("enchantmentSeed", GetRandomProvider().RandInt<unsigned int>()).asUInt(); m_EnchantmentSeed = Root.get("enchantmentSeed", GetRandomProvider().RandInt<unsigned int>()).asUInt();
Json::Value & JSON_KnownItems = root["knownItems"]; Json::Value & JSON_KnownItems = Root["knownItems"];
for (UInt32 i = 0; i < JSON_KnownItems.size(); i++) for (UInt32 i = 0; i < JSON_KnownItems.size(); i++)
{ {
cItem Item; cItem Item;
@ -1872,7 +1795,7 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World)
const auto & RecipeNameMap = cRoot::Get()->GetCraftingRecipes()->GetRecipeNameMap(); const auto & RecipeNameMap = cRoot::Get()->GetCraftingRecipes()->GetRecipeNameMap();
Json::Value & JSON_KnownRecipes = root["knownRecipes"]; Json::Value & JSON_KnownRecipes = Root["knownRecipes"];
for (UInt32 i = 0; i < JSON_KnownRecipes.size(); i++) for (UInt32 i = 0; i < JSON_KnownRecipes.size(); i++)
{ {
auto RecipeId = RecipeNameMap.find(JSON_KnownRecipes[i].asString()); auto RecipeId = RecipeNameMap.find(JSON_KnownRecipes[i].asString());
@ -1882,21 +1805,21 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World)
} }
} }
m_GameMode = static_cast<eGameMode>(root.get("gamemode", eGameMode_NotSet).asInt()); m_GameMode = static_cast<eGameMode>(Root.get("gamemode", eGameMode_NotSet).asInt());
if (m_GameMode == eGameMode_Creative) if (m_GameMode == eGameMode_Creative)
{ {
m_CanFly = true; m_CanFly = true;
} }
m_Inventory.LoadFromJson(root["inventory"]); m_Inventory.LoadFromJson(Root["inventory"]);
int equippedSlotNum = root.get("equippedItemSlot", 0).asInt(); int equippedSlotNum = Root.get("equippedItemSlot", 0).asInt();
m_Inventory.SetEquippedSlotNum(equippedSlotNum); m_Inventory.SetEquippedSlotNum(equippedSlotNum);
cEnderChestEntity::LoadFromJson(root["enderchestinventory"], m_EnderChestContents); cEnderChestEntity::LoadFromJson(Root["enderchestinventory"], m_EnderChestContents);
m_CurrentWorldName = root.get("world", "world").asString(); m_CurrentWorldName = Root.get("world", "world").asString();
a_World = cRoot::Get()->GetWorld(GetLoadedWorldName()); a_World = cRoot::Get()->GetWorld(GetLoadedWorldName());
if (a_World == nullptr) if (a_World == nullptr)
{ {
@ -1904,10 +1827,10 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World)
} }
m_LastBedPos.x = root.get("SpawnX", a_World->GetSpawnX()).asInt(); m_LastBedPos.x = Root.get("SpawnX", a_World->GetSpawnX()).asInt();
m_LastBedPos.y = root.get("SpawnY", a_World->GetSpawnY()).asInt(); m_LastBedPos.y = Root.get("SpawnY", a_World->GetSpawnY()).asInt();
m_LastBedPos.z = root.get("SpawnZ", a_World->GetSpawnZ()).asInt(); m_LastBedPos.z = Root.get("SpawnZ", a_World->GetSpawnZ()).asInt();
m_SpawnWorldName = root.get("SpawnWorld", cRoot::Get()->GetDefaultWorld()->GetName()).asString(); m_SpawnWorldName = Root.get("SpawnWorld", cRoot::Get()->GetDefaultWorld()->GetName()).asString();
try try
{ {
@ -1960,9 +1883,10 @@ void cPlayer::OpenHorseInventory()
bool cPlayer::SaveToDisk() void cPlayer::SaveToDisk()
{ {
cFile::CreateFolderRecursive(GetUUIDFolderName(m_UUID)); const auto & UUID = GetUUID();
cFile::CreateFolderRecursive(GetUUIDFolderName(UUID));
// create the JSON data // create the JSON data
Json::Value JSON_PlayerPosition; Json::Value JSON_PlayerPosition;
@ -2023,22 +1947,22 @@ bool cPlayer::SaveToDisk()
root["gamemode"] = static_cast<int>(m_GameMode); root["gamemode"] = static_cast<int>(m_GameMode);
auto JsonData = JsonUtils::WriteStyledString(root); auto JsonData = JsonUtils::WriteStyledString(root);
AString SourceFile = GetUUIDFileName(m_UUID); AString SourceFile = GetUUIDFileName(UUID);
cFile f; cFile f;
if (!f.Open(SourceFile, cFile::fmWrite)) if (!f.Open(SourceFile, cFile::fmWrite))
{ {
LOGWARNING("Error writing player \"%s\" to file \"%s\" - cannot open file. Player will lose their progress.", LOGWARNING("Error writing player \"%s\" to file \"%s\": cannot open file. Player will lose their progress",
GetName().c_str(), SourceFile.c_str() GetName().c_str(), SourceFile.c_str()
); );
return false; return;
} }
if (f.Write(JsonData.c_str(), JsonData.size()) != static_cast<int>(JsonData.size())) if (f.Write(JsonData.c_str(), JsonData.size()) != static_cast<int>(JsonData.size()))
{ {
LOGWARNING("Error writing player \"%s\" to file \"%s\" - cannot save data. Player will lose their progress. ", LOGWARNING("Error writing player \"%s\" to file \"%s\": cannot save data. Player will lose their progress",
GetName().c_str(), SourceFile.c_str() GetName().c_str(), SourceFile.c_str()
); );
return false; return;
} }
try try
@ -2050,11 +1974,8 @@ bool cPlayer::SaveToDisk()
} }
catch (...) catch (...)
{ {
LOGWARNING("Could not save stats for player %s", GetName().c_str()); LOGWARNING("Error writing player \"%s\" statistics to file", GetName().c_str());
return false;
} }
return true;
} }
@ -2316,9 +2237,11 @@ void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos, bool a_PreviousIs
void cPlayer::LoadRank(void) void cPlayer::LoadRank(void)
{ {
// Load the values from cRankManager: const auto & UUID = GetUUID();
cRankManager * RankMgr = cRoot::Get()->GetRankManager(); cRankManager * RankMgr = cRoot::Get()->GetRankManager();
m_Rank = RankMgr->GetPlayerRankName(m_UUID);
// Load the values from cRankManager:
m_Rank = RankMgr->GetPlayerRankName(UUID);
if (m_Rank.empty()) if (m_Rank.empty())
{ {
m_Rank = RankMgr->GetDefaultRank(); m_Rank = RankMgr->GetDefaultRank();
@ -2326,10 +2249,10 @@ void cPlayer::LoadRank(void)
else else
{ {
// Update the name: // Update the name:
RankMgr->UpdatePlayerName(m_UUID, GetName()); RankMgr->UpdatePlayerName(UUID, GetName());
} }
m_Permissions = RankMgr->GetPlayerPermissions(m_UUID); m_Permissions = RankMgr->GetPlayerPermissions(UUID);
m_Restrictions = RankMgr->GetPlayerRestrictions(m_UUID); m_Restrictions = RankMgr->GetPlayerRestrictions(UUID);
RankMgr->GetRankVisuals(m_Rank, m_MsgPrefix, m_MsgSuffix, m_MsgNameColorCode); RankMgr->GetRankVisuals(m_Rank, m_MsgPrefix, m_MsgSuffix, m_MsgNameColorCode);
// Break up the individual permissions on each dot, into m_SplitPermissions: // Break up the individual permissions on each dot, into m_SplitPermissions:
@ -2469,6 +2392,15 @@ bool cPlayer::DoesPlacingBlocksIntersectEntity(const sSetBlockVector & a_Blocks)
const cUUID & cPlayer::GetUUID(void) const
{
return m_ClientHandle->GetUUID();
}
bool cPlayer::PlaceBlocks(const sSetBlockVector & a_Blocks) bool cPlayer::PlaceBlocks(const sSetBlockVector & a_Blocks)
{ {
if (DoesPlacingBlocksIntersectEntity(a_Blocks)) if (DoesPlacingBlocksIntersectEntity(a_Blocks))

View File

@ -379,21 +379,18 @@ public:
void SetVisible( bool a_bVisible); // tolua_export void SetVisible( bool a_bVisible); // tolua_export
bool IsVisible(void) const { return m_bVisible; } // tolua_export bool IsVisible(void) const { return m_bVisible; } // tolua_export
/** Saves all player data, such as inventory, to JSON */ /** Saves all player data, such as inventory, to JSON. */
bool SaveToDisk(void); void SaveToDisk(void);
typedef cWorld * cWorldPtr; typedef cWorld * cWorldPtr;
/** Loads the player data from the disk file /** Loads the player data from the disk file.
Sets a_World to the world where the player will spawn, based on the stored world name or the default world by calling LoadFromFile() Sets a_World to the world where the player will spawn, based on the stored world name or the default world by calling LoadFromFile(). */
Returns true on success, false on failure void LoadFromDisk(cWorldPtr & a_World);
*/
bool LoadFromDisk(cWorldPtr & a_World);
/** Loads the player data from the specified file /** Loads the player data from the specified file.
Sets a_World to the world where the player will spawn, based on the stored world name or the default world Sets a_World to the world where the player will spawn, based on the stored world name or the default world.
Returns true on success, false on failure Returns true on success, false if the player wasn't found, and excepts with base std::runtime_error if the data couldn't be read or parsed. */
*/
bool LoadFromFile(const AString & a_FileName, cWorldPtr & a_World); bool LoadFromFile(const AString & a_FileName, cWorldPtr & a_World);
const AString & GetLoadedWorldName() const { return m_CurrentWorldName; } const AString & GetLoadedWorldName() const { return m_CurrentWorldName; }
@ -499,7 +496,7 @@ public:
bool DoesPlacingBlocksIntersectEntity(const sSetBlockVector & a_Blocks); bool DoesPlacingBlocksIntersectEntity(const sSetBlockVector & a_Blocks);
/** Returns the UUID that has been read from the client, or nil if not available. */ /** 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 const cUUID & GetUUID(void) const; // Exported in ManualBindings.cpp
// tolua_begin // tolua_begin
@ -507,7 +504,6 @@ public:
virtual bool CanFly(void) const { return m_CanFly; } virtual bool CanFly(void) const { return m_CanFly; }
/** (Re)loads the rank and permissions from the cRankManager. /** (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. */ Loads the m_Rank, m_Permissions, m_MsgPrefix, m_MsgSuffix and m_MsgNameColorCode members. */
void LoadRank(void); void LoadRank(void);
@ -718,10 +714,6 @@ private:
*/ */
bool m_bIsTeleporting; bool m_bIsTeleporting;
/** 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; AString m_CustomName;
/** Displayed skin part bit mask */ /** Displayed skin part bit mask */

View File

@ -117,9 +117,7 @@ cServer::cServer(void) :
m_MaxPlayers(0), m_MaxPlayers(0),
m_bIsHardcore(false), m_bIsHardcore(false),
m_TickThread(*this), m_TickThread(*this),
m_ShouldAuthenticate(false), m_ShouldAuthenticate(false)
m_ShouldLoadOfflinePlayerData(false),
m_ShouldLoadNamedPlayerData(true)
{ {
// Initialize the LuaStateTracker singleton before the app goes multithreaded: // Initialize the LuaStateTracker singleton before the app goes multithreaded:
cLuaStateTracker::GetStats(); cLuaStateTracker::GetStats();
@ -206,8 +204,6 @@ bool cServer::InitServer(cSettingsRepositoryInterface & a_Settings, bool a_Shoul
m_ShouldAllowMultiWorldTabCompletion = a_Settings.GetValueSetB("Server", "AllowMultiWorldTabCompletion", true); m_ShouldAllowMultiWorldTabCompletion = a_Settings.GetValueSetB("Server", "AllowMultiWorldTabCompletion", true);
m_ShouldLimitPlayerBlockChanges = a_Settings.GetValueSetB("AntiCheat", "LimitPlayerBlockChanges", true); m_ShouldLimitPlayerBlockChanges = a_Settings.GetValueSetB("AntiCheat", "LimitPlayerBlockChanges", true);
m_ShouldLoadOfflinePlayerData = a_Settings.GetValueSetB("PlayerData", "LoadOfflinePlayerData", false);
m_ShouldLoadNamedPlayerData = a_Settings.GetValueSetB("PlayerData", "LoadNamedPlayerData", true);
const auto ClientViewDistance = a_Settings.GetValueSetI("Server", "DefaultViewDistance", cClientHandle::DEFAULT_VIEW_DISTANCE); const auto ClientViewDistance = a_Settings.GetValueSetI("Server", "DefaultViewDistance", cClientHandle::DEFAULT_VIEW_DISTANCE);
if (ClientViewDistance < cClientHandle::MIN_VIEW_DISTANCE) if (ClientViewDistance < cClientHandle::MIN_VIEW_DISTANCE)

View File

@ -141,15 +141,6 @@ public:
/** Returns true if limit for number of block changes per tick by a player has been turned on in server settings. */ /** Returns true if limit for number of block changes per tick by a player has been turned on in server settings. */
bool ShouldLimitPlayerBlockChanges(void) const { return m_ShouldLimitPlayerBlockChanges; } bool ShouldLimitPlayerBlockChanges(void) const { return m_ShouldLimitPlayerBlockChanges; }
/** Returns true if offline UUIDs should be used to load data for players whose normal UUIDs cannot be found.
Loaded from the settings.ini [PlayerData].LoadOfflinePlayerData setting. */
bool ShouldLoadOfflinePlayerData(void) const { return m_ShouldLoadOfflinePlayerData; }
/** Returns true if old-style playernames should be used to load data for players whose regular datafiles cannot be found.
This allows a seamless transition from name-based to UUID-based player storage.
Loaded from the settings.ini [PlayerData].LoadNamedPlayerData setting. */
bool ShouldLoadNamedPlayerData(void) const { return m_ShouldLoadNamedPlayerData; }
/** Returns true if BungeeCord logins (that specify the player's UUID) are allowed. /** Returns true if BungeeCord logins (that specify the player's UUID) are allowed.
Read from settings, admins should set this to true only when they chain to BungeeCord, Read from settings, admins should set this to true only when they chain to BungeeCord,
it makes the server vulnerable to identity theft through direct connections. */ it makes the server vulnerable to identity theft through direct connections. */
@ -243,16 +234,6 @@ private:
/** True if limit for number of block changes per tick by a player should be enabled. */ /** True if limit for number of block changes per tick by a player should be enabled. */
bool m_ShouldLimitPlayerBlockChanges; bool m_ShouldLimitPlayerBlockChanges;
/** True if offline UUIDs should be used to load data for players whose normal UUIDs cannot be found.
This allows transitions from an offline (no-auth) server to an online one.
Loaded from the settings.ini [PlayerData].LoadOfflinePlayerData setting. */
bool m_ShouldLoadOfflinePlayerData;
/** True if old-style playernames should be used to load data for players whose regular datafiles cannot be found.
This allows a seamless transition from name-based to UUID-based player storage.
Loaded from the settings.ini [PlayerData].LoadNamedPlayerData setting. */
bool m_ShouldLoadNamedPlayerData;
/** True if BungeeCord handshake packets (with player UUID) should be accepted. */ /** True if BungeeCord handshake packets (with player UUID) should be accepted. */
bool m_ShouldAllowBungeeCord; bool m_ShouldAllowBungeeCord;