summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorandrew <xdotftw@gmail.com>2014-01-20 15:10:39 +0100
committerandrew <xdotftw@gmail.com>2014-01-20 15:10:39 +0100
commit7728f4bcbee7fa61f005c7b972685deb4bf04f2a (patch)
tree2aa40e20c9045a997abb25e17d2fa4890bf47e08
parentScoreboard improvements (diff)
downloadcuberite-7728f4bcbee7fa61f005c7b972685deb4bf04f2a.tar
cuberite-7728f4bcbee7fa61f005c7b972685deb4bf04f2a.tar.gz
cuberite-7728f4bcbee7fa61f005c7b972685deb4bf04f2a.tar.bz2
cuberite-7728f4bcbee7fa61f005c7b972685deb4bf04f2a.tar.lz
cuberite-7728f4bcbee7fa61f005c7b972685deb4bf04f2a.tar.xz
cuberite-7728f4bcbee7fa61f005c7b972685deb4bf04f2a.tar.zst
cuberite-7728f4bcbee7fa61f005c7b972685deb4bf04f2a.zip
-rw-r--r--src/Entities/Player.cpp22
-rw-r--r--src/Entities/Player.h7
-rw-r--r--src/Scoreboard.cpp166
-rw-r--r--src/Scoreboard.h85
-rw-r--r--src/WorldStorage/ScoreboardSerializer.cpp317
-rw-r--r--src/WorldStorage/ScoreboardSerializer.h48
-rw-r--r--src/WorldStorage/WSSAnvil.cpp2
7 files changed, 599 insertions, 48 deletions
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index d2fdba909..285aefd25 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -111,6 +111,8 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
m_LastJumpHeight = (float)(GetPosY());
m_LastGroundHeight = (float)(GetPosY());
m_Stance = GetPosY() + 1.62;
+
+ // UpdateTeam();
cRoot::Get()->GetServer()->PlayerCreated(this);
}
@@ -949,8 +951,13 @@ bool cPlayer::IsGameModeAdventure(void) const
-void cPlayer::SetTeam(cTeam* a_Team)
+void cPlayer::SetTeam(cTeam * a_Team)
{
+ if (m_Team == a_Team)
+ {
+ return;
+ }
+
if (m_Team)
{
m_Team->RemovePlayer(GetName());
@@ -968,6 +975,19 @@ void cPlayer::SetTeam(cTeam* a_Team)
+cTeam * cPlayer::UpdateTeam(void)
+{
+ cScoreboard * Scoreboard = m_World->GetScoreBoard();
+
+ m_Team = Scoreboard->QueryPlayerTeam(GetName());
+
+ return m_Team;
+}
+
+
+
+
+
void cPlayer::OpenWindow(cWindow * a_Window)
{
if (a_Window != m_CurrentWindow)
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index 52e629dc3..52ba2065c 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -155,10 +155,13 @@ public:
AString GetIP(void) const { return m_IP; } // tolua_export
/// Returns the associated team, NULL if none
- cTeam* GetTeam(void) { return m_Team; } // tolua_export
+ cTeam * GetTeam(void) { return m_Team; } // tolua_export
/// Sets the player team, NULL if none
- void SetTeam(cTeam* a_Team);
+ void SetTeam(cTeam * a_Team);
+
+ /// Forces the player to query the scoreboard for his team
+ cTeam * UpdateTeam(void);
// tolua_end
diff --git a/src/Scoreboard.cpp b/src/Scoreboard.cpp
index 539316356..864837d3d 100644
--- a/src/Scoreboard.cpp
+++ b/src/Scoreboard.cpp
@@ -11,22 +11,74 @@
-cObjective::cObjective(cObjective::eType a_Type) : m_Type(a_Type)
-{}
+AString cObjective::TypeToString(eType a_Type)
+{
+ switch (a_Type)
+ {
+ case E_TYPE_DUMMY: return "dummy";
+ case E_TYPE_DEATH_COUNT: return "deathCount";
+ case E_TYPE_PLAYER_KILL_COUNT: return "playerKillCount";
+ case E_TYPE_TOTAL_KILL_COUNT: return "totalKillCount";
+ case E_TYPE_HEALTH: return "health";
+ case E_TYPE_ACHIEVEMENT: return "achievement";
+ case E_TYPE_STAT: return "stat";
+ case E_TYPE_STAT_ITEM_CRAFT: return "stat.craftItem";
+ case E_TYPE_STAT_ITEM_USE: return "stat.useItem";
+ case E_TYPE_STAT_ITEM_BREAK: return "stat.breakItem";
+ case E_TYPE_STAT_BLOCK_MINE: return "stat.mineBlock";
+ case E_TYPE_STAT_ENTITY_KILL: return "stat.killEntity";
+ case E_TYPE_STAT_ENTITY_KILLED_BY: return "stat.entityKilledBy";
+
+ default: return "";
+ }
+}
-void cObjective::SetDisplaySlot(cObjective::eDisplaySlot a_Display)
+cObjective::eType cObjective::StringToType(const AString & a_Name)
{
- m_Display = a_Display;
+ static struct {
+ eType m_Type;
+ const char * m_String;
+ } TypeMap [] =
+ {
+ {E_TYPE_DUMMY, "dummy"},
+ {E_TYPE_DEATH_COUNT, "deathCount"},
+ {E_TYPE_PLAYER_KILL_COUNT, "playerKillCount"},
+ {E_TYPE_TOTAL_KILL_COUNT, "totalKillCount"},
+ {E_TYPE_HEALTH, "health"},
+ {E_TYPE_ACHIEVEMENT, "achievement"},
+ {E_TYPE_STAT, "stat"},
+ {E_TYPE_STAT_ITEM_CRAFT, "stat.craftItem"},
+ {E_TYPE_STAT_ITEM_USE, "stat.useItem"},
+ {E_TYPE_STAT_ITEM_BREAK, "stat.breakItem"},
+ {E_TYPE_STAT_BLOCK_MINE, "stat.mineBlock"},
+ {E_TYPE_STAT_ENTITY_KILL, "stat.killEntity"},
+ {E_TYPE_STAT_ENTITY_KILLED_BY, "stat.entityKilledBy"}
+ };
+ for (size_t i = 0; i < ARRAYCOUNT(TypeMap); i++)
+ {
+ if (NoCaseCompare(TypeMap[i].m_String, a_Name) == 0)
+ {
+ return TypeMap[i].m_Type;
+ }
+ } // for i - TypeMap[]
+ return E_TYPE_DUMMY;
}
+cObjective::cObjective(const AString & a_DisplayName, cObjective::eType a_Type) : m_DisplayName(a_DisplayName), m_Type(a_Type)
+{}
+
+
+
+
+
void cObjective::Reset(void)
{
m_Scores.clear();
@@ -132,6 +184,17 @@ bool cTeam::RemovePlayer(const AString & a_Name)
+bool cTeam::HasPlayer(const AString & a_Name) const
+{
+ cPlayerNameSet::const_iterator it = m_Players.find(a_Name);
+
+ return it != m_Players.end();
+}
+
+
+
+
+
void cTeam::Reset(void)
{
m_Players.clear();
@@ -149,11 +212,23 @@ unsigned int cTeam::GetNumPlayers(void) const
-cObjective* cScoreboard::RegisterObjective(const AString & a_Name, cObjective::eType a_Type)
+cScoreboard::cScoreboard()
{
- cObjective Objective(a_Type);
+ for (int i = 0; i < (int) E_DISPLAY_SLOT_COUNT; ++i)
+ {
+ m_Display[i] = NULL;
+ }
+}
+
+
+
- std::pair<ObjectiveMap::iterator, bool> Status = m_Objectives.insert(NamedObjective(a_Name, Objective));
+
+cObjective* cScoreboard::RegisterObjective(const AString & a_Name, const AString & a_DisplayName, cObjective::eType a_Type)
+{
+ cObjective Objective(a_DisplayName, a_Type);
+
+ std::pair<cObjectiveMap::iterator, bool> Status = m_Objectives.insert(cNamedObjective(a_Name, Objective));
return Status.second ? &Status.first->second : NULL;
}
@@ -164,7 +239,7 @@ cObjective* cScoreboard::RegisterObjective(const AString & a_Name, cObjective::e
bool cScoreboard::RemoveObjective(const AString & a_Name)
{
- ObjectiveMap::iterator it = m_Objectives.find(a_Name);
+ cObjectiveMap::iterator it = m_Objectives.find(a_Name);
if (it == m_Objectives.end())
{
@@ -180,9 +255,9 @@ bool cScoreboard::RemoveObjective(const AString & a_Name)
-cObjective* cScoreboard::GetObjective(const AString & a_Name)
+cObjective * cScoreboard::GetObjective(const AString & a_Name)
{
- ObjectiveMap::iterator it = m_Objectives.find(a_Name);
+ cObjectiveMap::iterator it = m_Objectives.find(a_Name);
if (it == m_Objectives.end())
{
@@ -198,14 +273,14 @@ cObjective* cScoreboard::GetObjective(const AString & a_Name)
-cTeam* cScoreboard::RegisterTeam(
+cTeam * cScoreboard::RegisterTeam(
const AString & a_Name, const AString & a_DisplayName,
const AString & a_Prefix, const AString & a_Suffix
)
{
cTeam Team(a_Name, a_DisplayName, a_Prefix, a_Suffix);
- std::pair<TeamMap::iterator, bool> Status = m_Teams.insert(NamedTeam(a_Name, Team));
+ std::pair<cTeamMap::iterator, bool> Status = m_Teams.insert(cNamedTeam(a_Name, Team));
return Status.second ? &Status.first->second : NULL;
}
@@ -216,7 +291,7 @@ cTeam* cScoreboard::RegisterTeam(
bool cScoreboard::RemoveTeam(const AString & a_Name)
{
- TeamMap::iterator it = m_Teams.find(a_Name);
+ cTeamMap::iterator it = m_Teams.find(a_Name);
if (it == m_Teams.end())
{
@@ -232,9 +307,9 @@ bool cScoreboard::RemoveTeam(const AString & a_Name)
-cTeam* cScoreboard::GetTeam(const AString & a_Name)
+cTeam * cScoreboard::GetTeam(const AString & a_Name)
{
- TeamMap::iterator it = m_Teams.find(a_Name);
+ cTeamMap::iterator it = m_Teams.find(a_Name);
if (it == m_Teams.end())
{
@@ -250,9 +325,50 @@ cTeam* cScoreboard::GetTeam(const AString & a_Name)
+cTeam * cScoreboard::QueryPlayerTeam(const AString & a_Name)
+{
+ for (cTeamMap::iterator it = m_Teams.begin(); it != m_Teams.end(); ++it)
+ {
+ if (it->second.HasPlayer(a_Name))
+ {
+ return &it->second;
+ }
+ }
+
+ return NULL;
+}
+
+
+
+
+
+void cScoreboard::SetDisplay(const AString & a_Objective, eDisplaySlot a_Slot)
+{
+ ASSERT(a_Slot < E_DISPLAY_SLOT_COUNT);
+
+ cObjective * Objective = GetObjective(a_Objective);
+
+ m_Display[a_Slot] = Objective;
+}
+
+
+
+
+
+cObjective* cScoreboard::GetObjectiveIn(eDisplaySlot a_Slot)
+{
+ ASSERT(a_Slot < E_DISPLAY_SLOT_COUNT);
+
+ return m_Display[a_Slot];
+}
+
+
+
+
+
void cScoreboard::ForEachObjectiveWith(cObjective::eType a_Type, cObjectiveCallback& a_Callback)
{
- for (ObjectiveMap::iterator it = m_Objectives.begin(); it != m_Objectives.end(); ++it)
+ for (cObjectiveMap::iterator it = m_Objectives.begin(); it != m_Objectives.end(); ++it)
{
if (it->second.GetType() == a_Type)
{
@@ -268,3 +384,21 @@ void cScoreboard::ForEachObjectiveWith(cObjective::eType a_Type, cObjectiveCallb
+
+unsigned int cScoreboard::GetNumObjectives(void) const
+{
+ return m_Objectives.size();
+}
+
+
+
+
+
+unsigned int cScoreboard::GetNumTeams(void) const
+{
+ return m_Teams.size();
+}
+
+
+
+
diff --git a/src/Scoreboard.h b/src/Scoreboard.h
index 7993b1333..f7285a9cf 100644
--- a/src/Scoreboard.h
+++ b/src/Scoreboard.h
@@ -24,6 +24,7 @@ typedef cItemCallback<cObjective> cObjectiveCallback;
class cObjective
{
public:
+
typedef int Score;
enum eType
@@ -47,21 +48,17 @@ public:
E_TYPE_STAT_ENTITY_KILLED_BY
};
- enum eDisplaySlot
- {
- E_DISPLAY_SLOT_LIST,
- E_DISPLAY_SLOT_SIDEBAR,
- E_DISPLAY_SLOT_NAME
- };
+ static AString TypeToString(eType a_Type);
+
+ static eType StringToType(const AString & a_Name);
public:
- cObjective(eType a_Type);
- eType GetType(void) const { return m_Type; }
+ cObjective(const AString & a_DisplayName, eType a_Type);
- eDisplaySlot GetDisplaySlot(void) const { return m_Display; }
+ eType GetType(void) const { return m_Type; }
- void SetDisplaySlot(eDisplaySlot a_Display);
+ const AString & GetDisplayName(void) const { return m_DisplayName; }
/// Resets the objective
void Reset(void);
@@ -82,15 +79,17 @@ public:
Score SubScore(const AString & a_Name, Score a_Delta);
private:
+
typedef std::pair<AString, Score> TrackedPlayer;
typedef std::map<AString, Score> ScoreMap;
ScoreMap m_Scores;
+ AString m_DisplayName;
+
eType m_Type;
- eDisplaySlot m_Display;
};
@@ -112,6 +111,9 @@ public:
/// Removes a player from the team
bool RemovePlayer(const AString & a_Name);
+ /// Returns whether the specified player is in this team
+ bool HasPlayer(const AString & a_Name) const;
+
/// Removes all registered players
void Reset(void);
@@ -127,8 +129,8 @@ public:
const AString & GetPrefix(void) const { return m_Prefix; }
const AString & GetSuffix(void) const { return m_Suffix; }
- void SetFriendlyFire(bool a_Flag);
- void SetCanSeeFriendlyInvisible(bool a_Flag);
+ void SetFriendlyFire(bool a_Flag) { m_AllowsFriendlyFire = a_Flag; }
+ void SetCanSeeFriendlyInvisible(bool a_Flag) { m_CanSeeFriendlyInvisible = a_Flag; }
void SetDisplayName(const AString & a_Name);
@@ -137,6 +139,8 @@ public:
private:
+ typedef std::set<AString> cPlayerNameSet;
+
bool m_AllowsFriendlyFire;
bool m_CanSeeFriendlyInvisible;
@@ -146,10 +150,8 @@ private:
AString m_Prefix;
AString m_Suffix;
- // TODO 2014-01-19 xdot: Potential optimization - vector/list
- typedef std::set<AString> PlayerNameSet;
+ cPlayerNameSet m_Players;
- PlayerNameSet m_Players;
};
@@ -159,41 +161,68 @@ private:
class cScoreboard
{
public:
- cScoreboard() {}
+
+ enum eDisplaySlot
+ {
+ E_DISPLAY_SLOT_LIST = 0,
+ E_DISPLAY_SLOT_SIDEBAR,
+ E_DISPLAY_SLOT_NAME,
+
+ E_DISPLAY_SLOT_COUNT
+ };
+
+
+public:
+
+ cScoreboard();
/// Registers a new scoreboard objective, returns the cObjective instance, NULL on name collision
- cObjective* RegisterObjective(const AString & a_Name, cObjective::eType a_Type);
+ cObjective * RegisterObjective(const AString & a_Name, const AString & a_DisplayName, cObjective::eType a_Type);
/// Removes a registered objective, returns true if operation was successful
bool RemoveObjective(const AString & a_Name);
/// Retrieves the objective with the specified name, NULL if not found
- cObjective* GetObjective(const AString & a_Name);
+ cObjective * GetObjective(const AString & a_Name);
/// Registers a new team, returns the cTeam instance, NULL on name collision
- cTeam* RegisterTeam(const AString & a_Name, const AString & a_DisplayName,
- const AString & a_Prefix, const AString & a_Suffix);
+ cTeam * RegisterTeam(const AString & a_Name, const AString & a_DisplayName, const AString & a_Prefix, const AString & a_Suffix);
/// Removes a registered team, returns true if operation was successful
bool RemoveTeam(const AString & a_Name);
/// Retrieves the team with the specified name, NULL if not found
- cTeam* GetTeam(const AString & a_Name);
+ cTeam * GetTeam(const AString & a_Name);
+
+ cTeam * QueryPlayerTeam(const AString & a_Name); // WARNING: O(n logn)
+
+ void SetDisplay(const AString & a_Objective, eDisplaySlot a_Slot);
+
+ cObjective* GetObjectiveIn(eDisplaySlot a_Slot);
/// Execute callback for each objective with the specified type
void ForEachObjectiveWith(cObjective::eType a_Type, cObjectiveCallback& a_Callback);
+ unsigned int GetNumObjectives(void) const;
+
+ unsigned int GetNumTeams(void) const;
+
+
private:
- typedef std::pair<AString, cObjective> NamedObjective;
- typedef std::pair<AString, cTeam> NamedTeam;
- typedef std::map<AString, cObjective> ObjectiveMap;
- typedef std::map<AString, cTeam> TeamMap;
+ typedef std::pair<AString, cObjective> cNamedObjective;
+ typedef std::pair<AString, cTeam> cNamedTeam;
+
+ typedef std::map<AString, cObjective> cObjectiveMap;
+ typedef std::map<AString, cTeam> cTeamMap;
// TODO 2014-01-19 xdot: Potential optimization - Sort objectives based on type
- ObjectiveMap m_Objectives;
+ cObjectiveMap m_Objectives;
+
+ cTeamMap m_Teams;
+
+ cObjective* m_Display[E_DISPLAY_SLOT_COUNT];
- TeamMap m_Teams;
} ;
diff --git a/src/WorldStorage/ScoreboardSerializer.cpp b/src/WorldStorage/ScoreboardSerializer.cpp
new file mode 100644
index 000000000..c2f13a092
--- /dev/null
+++ b/src/WorldStorage/ScoreboardSerializer.cpp
@@ -0,0 +1,317 @@
+
+// ScoreboardSerializer.cpp
+
+
+#include "Globals.h"
+#include "ScoreboardSerializer.h"
+#include "../StringCompression.h"
+#include "zlib/zlib.h"
+#include "FastNBT.h"
+
+#include "../Scoreboard.h"
+
+
+
+
+#define SCOREBOARD_INFLATE_MAX 16 KiB
+
+
+
+
+
+cScoreboardSerializer::cScoreboardSerializer(const AString & a_WorldName, cScoreboard* a_ScoreBoard)
+ : m_ScoreBoard(a_ScoreBoard)
+{
+ Printf(m_Path, "%s/data/scoreboard.dat", a_WorldName.c_str());
+}
+
+
+
+
+
+bool cScoreboardSerializer::Load(void)
+{
+ cFile File;
+
+ if (!File.Open(m_Path, cFile::fmReadWrite))
+ {
+ return false;
+ }
+
+ AString Data;
+
+ File.ReadRestOfFile(Data);
+
+ File.Close();
+
+ char Uncompressed[SCOREBOARD_INFLATE_MAX];
+ z_stream strm;
+ strm.zalloc = (alloc_func)NULL;
+ strm.zfree = (free_func)NULL;
+ strm.opaque = NULL;
+ inflateInit(&strm);
+ strm.next_out = (Bytef *)Uncompressed;
+ strm.avail_out = sizeof(Uncompressed);
+ strm.next_in = (Bytef *)Data.data();
+ strm.avail_in = Data.size();
+ int res = inflate(&strm, Z_FINISH);
+ inflateEnd(&strm);
+ if (res != Z_STREAM_END)
+ {
+ return false;
+ }
+
+ // Parse the NBT data:
+ cParsedNBT NBT(Uncompressed, strm.total_out);
+ if (!NBT.IsValid())
+ {
+ // NBT Parsing failed
+ return false;
+ }
+
+ return LoadScoreboardFromNBT(NBT);
+}
+
+
+
+
+
+bool cScoreboardSerializer::Save(void)
+{
+ cFastNBTWriter Writer;
+
+ Writer.BeginCompound("");
+
+ SaveScoreboardToNBT(Writer);
+
+ Writer.EndCompound();
+ Writer.Finish();
+
+ #ifdef _DEBUG
+ cParsedNBT TestParse(Writer.GetResult().data(), Writer.GetResult().size());
+ ASSERT(TestParse.IsValid());
+ #endif // _DEBUG
+
+ gzFile gz = gzopen((FILE_IO_PREFIX + m_Path).c_str(), "wb");
+ if (gz != NULL)
+ {
+ gzwrite(gz, Writer.GetResult().data(), Writer.GetResult().size());
+ }
+ gzclose(gz);
+
+ return true;
+}
+
+
+
+
+
+void cScoreboardSerializer::SaveScoreboardToNBT(cFastNBTWriter & a_Writer)
+{
+ a_Writer.BeginCompound("Data");
+ a_Writer.BeginList("Objectives", TAG_Compound);
+
+ a_Writer.EndList();
+
+ a_Writer.BeginList("PlayerScores", TAG_Compound);
+
+ a_Writer.EndList();
+
+ a_Writer.BeginList("Teams", TAG_Compound);
+
+ a_Writer.EndList();
+ a_Writer.EndCompound();
+
+ a_Writer.BeginCompound("DisplaySlots");
+
+ a_Writer.EndCompound();
+}
+
+
+
+
+
+bool cScoreboardSerializer::LoadScoreboardFromNBT(const cParsedNBT & a_NBT)
+{
+ int Data = a_NBT.FindChildByName(0, "Data");
+ if (Data < 0)
+ {
+ return false;
+ }
+
+ int Objectives = a_NBT.FindChildByName(Data, "Objectives");
+ if (Objectives < 0)
+ {
+ return false;
+ }
+
+ for (int Child = a_NBT.GetFirstChild(Objectives); Child >= 0; Child = a_NBT.GetNextSibling(Child))
+ {
+ AString CriteriaName, DisplayName, Name;
+
+ int CurrLine = a_NBT.FindChildByName(Child, "CriteriaName");
+ if (CurrLine >= 0)
+ {
+ CriteriaName = a_NBT.GetString(CurrLine);
+ }
+
+ CurrLine = a_NBT.FindChildByName(Child, "DisplayName");
+ if (CurrLine >= 0)
+ {
+ DisplayName = a_NBT.GetString(CurrLine);
+ }
+
+ CurrLine = a_NBT.FindChildByName(Child, "Name");
+ if (CurrLine >= 0)
+ {
+ Name = a_NBT.GetString(CurrLine);
+ }
+
+ cObjective::eType Type = cObjective::StringToType(CriteriaName);
+
+ m_ScoreBoard->RegisterObjective(Name, DisplayName, Type);
+ }
+
+ int PlayerScores = a_NBT.FindChildByName(Data, "PlayerScores");
+ if (PlayerScores < 0)
+ {
+ return false;
+ }
+
+ for (int Child = a_NBT.GetFirstChild(PlayerScores); Child >= 0; Child = a_NBT.GetNextSibling(Child))
+ {
+ AString Name, ObjectiveName;
+
+ cObjective::Score Score;
+
+ int CurrLine = a_NBT.FindChildByName(Child, "Score");
+ if (CurrLine >= 0)
+ {
+ Score = a_NBT.GetInt(CurrLine);
+ }
+
+ CurrLine = a_NBT.FindChildByName(Child, "Name");
+ if (CurrLine >= 0)
+ {
+ Name = a_NBT.GetString(CurrLine);
+ }
+
+ CurrLine = a_NBT.FindChildByName(Child, "Objective");
+ if (CurrLine >= 0)
+ {
+ ObjectiveName = a_NBT.GetString(CurrLine);
+ }
+
+ cObjective * Objective = m_ScoreBoard->GetObjective(ObjectiveName);
+
+ if (Objective)
+ {
+ Objective->SetScore(Name, Score);
+ }
+ }
+
+ int Teams = a_NBT.FindChildByName(Data, "Teams");
+ if (Teams < 0)
+ {
+ return false;
+ }
+
+ for (int Child = a_NBT.GetFirstChild(Teams); Child >= 0; Child = a_NBT.GetNextSibling(Child))
+ {
+ AString Name, DisplayName, Prefix, Suffix;
+
+ bool AllowsFriendlyFire, CanSeeFriendlyInvisible;
+
+ int CurrLine = a_NBT.FindChildByName(Child, "Name");
+ if (CurrLine >= 0)
+ {
+ Name = a_NBT.GetInt(CurrLine);
+ }
+
+ CurrLine = a_NBT.FindChildByName(Child, "DisplayName");
+ if (CurrLine >= 0)
+ {
+ DisplayName = a_NBT.GetInt(CurrLine);
+ }
+
+ CurrLine = a_NBT.FindChildByName(Child, "Prefix");
+ if (CurrLine >= 0)
+ {
+ Prefix = a_NBT.GetInt(CurrLine);
+ }
+
+ CurrLine = a_NBT.FindChildByName(Child, "Suffix");
+ if (CurrLine >= 0)
+ {
+ Suffix = a_NBT.GetInt(CurrLine);
+ }
+
+ CurrLine = a_NBT.FindChildByName(Child, "AllowFriendlyFire");
+ if (CurrLine >= 0)
+ {
+ AllowsFriendlyFire = a_NBT.GetInt(CurrLine);
+ }
+
+ CurrLine = a_NBT.FindChildByName(Child, "SeeFriendlyInvisibles");
+ if (CurrLine >= 0)
+ {
+ CanSeeFriendlyInvisible = a_NBT.GetInt(CurrLine);
+ }
+
+ cTeam * Team = m_ScoreBoard->RegisterTeam(Name, DisplayName, Prefix, Suffix);
+
+ Team->SetFriendlyFire(AllowsFriendlyFire);
+ Team->SetCanSeeFriendlyInvisible(CanSeeFriendlyInvisible);
+
+ int Players = a_NBT.FindChildByName(Child, "Players");
+ if (Players < 0)
+ {
+ continue;
+ }
+
+ for (int ChildB = a_NBT.GetFirstChild(Players); ChildB >= 0; ChildB = a_NBT.GetNextSibling(ChildB))
+ {
+ Team->AddPlayer(a_NBT.GetString(ChildB));
+ }
+ }
+
+ int DisplaySlots = a_NBT.FindChildByName(0, "DisplaySlots");
+ if (DisplaySlots < 0)
+ {
+ return false;
+ }
+
+ int CurrLine = a_NBT.FindChildByName(DisplaySlots, "slot_0");
+ if (CurrLine >= 0)
+ {
+ AString Name = a_NBT.GetString(CurrLine);
+
+ m_ScoreBoard->SetDisplay(Name, cScoreboard::E_DISPLAY_SLOT_LIST);
+ }
+
+ CurrLine = a_NBT.FindChildByName(DisplaySlots, "slot_1");
+ if (CurrLine >= 0)
+ {
+ AString Name = a_NBT.GetString(CurrLine);
+
+ m_ScoreBoard->SetDisplay(Name, cScoreboard::E_DISPLAY_SLOT_SIDEBAR);
+ }
+
+ CurrLine = a_NBT.FindChildByName(DisplaySlots, "slot_2");
+ if (CurrLine >= 0)
+ {
+ AString Name = a_NBT.GetString(CurrLine);
+
+ m_ScoreBoard->SetDisplay(Name, cScoreboard::E_DISPLAY_SLOT_NAME);
+ }
+
+ return true;
+}
+
+
+
+
+
+
+
+
diff --git a/src/WorldStorage/ScoreboardSerializer.h b/src/WorldStorage/ScoreboardSerializer.h
new file mode 100644
index 000000000..2a4e0767e
--- /dev/null
+++ b/src/WorldStorage/ScoreboardSerializer.h
@@ -0,0 +1,48 @@
+
+// ScoreboardSerializer.h
+
+// Declares the cScoreboardSerializer class that is used for saving scoreboards into NBT format used by Anvil
+
+
+
+
+
+#pragma once
+
+
+
+
+
+// fwd:
+class cFastNBTWriter;
+class cParsedNBT;
+class cScoreboard;
+
+
+
+
+class cScoreboardSerializer
+{
+public:
+ cScoreboardSerializer(const AString & a_WorldName, cScoreboard* a_ScoreBoard);
+
+ /// Try to load the scoreboard
+ bool Load(void);
+
+ /// Try to save the scoreboard
+ bool Save(void);
+
+private:
+
+ void SaveScoreboardToNBT(cFastNBTWriter & a_Writer);
+
+ bool LoadScoreboardFromNBT(const cParsedNBT & a_NBT);
+
+ cScoreboard* m_ScoreBoard;
+
+ AString m_Path;
+} ;
+
+
+
+
diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp
index 96a77152b..600eb0a51 100644
--- a/src/WorldStorage/WSSAnvil.cpp
+++ b/src/WorldStorage/WSSAnvil.cpp
@@ -1935,7 +1935,7 @@ bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_N
return false;
}
a_Entity.SetYaw(Rotation[0]);
- a_Entity.SetRoll (Rotation[1]);
+ a_Entity.SetRoll(Rotation[1]);
return true;
}