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) -{} - - - - - -void cObjective::SetDisplaySlot(cObjective::eDisplaySlot a_Display) +AString cObjective::TypeToString(eType a_Type) { - m_Display = a_Display; + 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 ""; + } } +cObjective::eType cObjective::StringToType(const AString & a_Name) +{ + 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 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 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 Status = m_Teams.insert(NamedTeam(a_Name, Team)); + std::pair 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 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); + + cObjective(const AString & a_DisplayName, eType a_Type); eType GetType(void) const { return m_Type; } - eDisplaySlot GetDisplaySlot(void) const { return m_Display; } - - 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 TrackedPlayer; typedef std::map 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 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 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); -private: - typedef std::pair NamedObjective; - typedef std::pair NamedTeam; + unsigned int GetNumObjectives(void) const; - typedef std::map ObjectiveMap; - typedef std::map TeamMap; + unsigned int GetNumTeams(void) const; + + +private: + + typedef std::pair cNamedObjective; + typedef std::pair cNamedTeam; + + typedef std::map cObjectiveMap; + typedef std::map 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; }