From 2b943610598c193a349107fd9345d321724aff98 Mon Sep 17 00:00:00 2001 From: andrew Date: Sun, 19 Jan 2014 14:20:57 +0200 Subject: [PATCH 1/7] Basic scoreboard implementation --- src/Entities/Player.cpp | 52 +++++++ src/Entities/Player.h | 11 +- src/Scoreboard.cpp | 301 ++++++++++++++++++++++++++++++++++++++++ src/Scoreboard.h | 207 +++++++++++++++++++++++++++ src/World.h | 6 + 5 files changed, 576 insertions(+), 1 deletion(-) create mode 100644 src/Scoreboard.cpp create mode 100644 src/Scoreboard.h diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index c1f2456eb..4f3c6138b 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -74,6 +74,7 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) , m_IsChargingBow(false) , m_BowCharge(0) , m_FloaterID(-1) + , m_Team(NULL) { LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d", a_PlayerName.c_str(), a_Client->GetIPString().c_str(), @@ -790,6 +791,20 @@ void cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI) return; } } + + if ((a_TDI.Attacker != NULL) && (a_TDI.Attacker->IsPlayer())) + { + cPlayer* Attacker = (cPlayer*) a_TDI.Attacker; + + if ((m_Team != NULL) && (m_Team == Attacker->m_Team)) + { + if (!m_Team->GetFriendlyFire()) + { + // Friendly fire is disabled + return; + } + } + } super::DoTakeDamage(a_TDI); @@ -836,6 +851,24 @@ void cPlayer::KilledBy(cEntity * a_Killer) GetWorld()->BroadcastChat(Printf("%s[DEATH] %s%s was killed by a %s", cChatColor::Red.c_str(), cChatColor::White.c_str(), GetName().c_str(), KillerClass.c_str())); } + + class cIncrementCounterCB + : public cObjectiveCallback + { + AString m_Name; + public: + cIncrementCounterCB(const AString & a_Name) : m_Name(a_Name) {} + + virtual bool Item(cObjective * a_Objective) override + { + a_Objective->AddScore(m_Name, 1); + } + } IncrementCounter (GetName()); + + cScoreboard* Scoreboard = m_World->GetScoreBoard(); + + // Update scoreboard objectives + Scoreboard->ForEachObjectiveWith(E_OBJECTIVE_DEATH_COUNT, IncrementCounter); } @@ -916,6 +949,25 @@ bool cPlayer::IsGameModeAdventure(void) const +void cPlayer::SetTeam(cTeam* a_Team) +{ + if (m_Team) + { + m_Team->RemovePlayer(this); + } + + m_Team = a_Team; + + if (m_Team) + { + m_Team->AddPlayer(this); + } +} + + + + + void cPlayer::OpenWindow(cWindow * a_Window) { if (a_Window != m_CurrentWindow) diff --git a/src/Entities/Player.h b/src/Entities/Player.h index bf3ca08e8..52e629dc3 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -13,6 +13,7 @@ class cGroup; class cWindow; class cClientHandle; +class cTeam; @@ -153,6 +154,12 @@ 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 + + /// Sets the player team, NULL if none + void SetTeam(cTeam* a_Team); + // tolua_end void SetIP(const AString & a_IP); @@ -456,6 +463,8 @@ protected: int m_FloaterID; + cTeam* m_Team; + void ResolvePermissions(void); @@ -463,7 +472,7 @@ protected: virtual void Destroyed(void); - /// Filters out damage for creative mode + /// Filters out damage for creative mode/friendly fire virtual void DoTakeDamage(TakeDamageInfo & TDI) override; /// Called in each tick to handle food-related processing diff --git a/src/Scoreboard.cpp b/src/Scoreboard.cpp new file mode 100644 index 000000000..1d2711ca0 --- /dev/null +++ b/src/Scoreboard.cpp @@ -0,0 +1,301 @@ + +// Scoreboard.cpp + +// Implementation of a scoreboard that keeps track of specified objectives + +#include "Globals.h" + +#include "Scoreboard.h" + + + + + +cObjective::cObjective(eObjectiveType a_Type) : m_Type(a_Type) +{} + + + + + +void cObjective::SetDisplaySlot(eDisplaySlot a_Display) +{ + m_Display = a_Display; +} + + + + + +void cObjective::Reset(void) +{ + m_Scores.clear(); +} + + + + + +cObjective::Score cObjective::GetScore(const AString & a_Name) const +{ + ScoreMap::const_iterator it = m_Scores.find(a_Name); + + if (it == m_Scores.end()) + { + return 0; + } + else + { + return it->second; + } +} + + + + + +void cObjective::SetScore(const AString & a_Name, cObjective::Score a_Score) +{ + m_Scores[a_Name] = a_Score; +} + + + + + +void cObjective::ResetScore(const AString & a_Name) +{ + m_Scores.erase(a_Name); +} + + + + + +cObjective::Score cObjective::AddScore(const AString & a_Name, cObjective::Score a_Delta) +{ + // TODO 2014-01-19 xdot: Potential optimization - Reuse iterator + Score NewScore = m_Scores[a_Name] + a_Delta; + + m_Scores[a_Name] = NewScore; + + return NewScore; +} + + + + + +cObjective::Score cObjective::SubScore(const AString & a_Name, cObjective::Score a_Delta) +{ + // TODO 2014-01-19 xdot: Potential optimization - Reuse iterator + Score NewScore = m_Scores[a_Name] - a_Delta; + + m_Scores[a_Name] = NewScore; + + return NewScore; +} + + + + + +cTeam::cTeam(const AString & a_Name, const AString & a_DisplayName, + const AString & a_Prefix, const AString & a_Suffix) + : m_FriendlyFire(true) + , m_SeeFriendlyInvisible(false) + , m_Name(a_Name) + , m_DisplayName(a_DisplayName) + , m_Prefix(a_Prefix) + , m_Suffix(a_Suffix) +{} + + + + + +bool cTeam::AddPlayer(cPlayer * a_Player) +{ + return m_Players.insert(a_Player).second; +} + + + + + +bool cTeam::RemovePlayer(cPlayer * a_Player) +{ + return m_Players.erase(a_Player) > 0; +} + + + + + +void cTeam::Reset(void) +{ + m_Players.clear(); +} + + + + +unsigned int cTeam::GetNumPlayers(void) const +{ + return m_Players.size(); +} + + + + + +cScoreboard::~cScoreboard() +{ + for (ObjectiveMap::iterator it = m_Objectives.begin(); it != m_Objectives.end(); ++it) + { + delete it->second; + } + + for (TeamMap::iterator it = m_Teams.begin(); it != m_Teams.end(); ++it) + { + delete it->second; + } +} + + + + + +cObjective* cScoreboard::RegisterObjective(const AString & a_Name, eObjectiveType a_Type) +{ + cObjective* Objective = new cObjective(a_Type); + + bool Status = m_Objectives.insert(NamedObjective(a_Name, Objective)).second; + + if (Status) + { + return Objective; + } + else + { + delete Objective; + return NULL; + } +} + + + + + +bool cScoreboard::RemoveObjective(const AString & a_Name) +{ + ObjectiveMap::iterator it = m_Objectives.find(a_Name); + + if (it == m_Objectives.end()) + { + return false; + } + + m_Objectives.erase(it); + + return true; +} + + + + + +cObjective* cScoreboard::GetObjective(const AString & a_Name) +{ + ObjectiveMap::iterator it = m_Objectives.find(a_Name); + + if (it == m_Objectives.end()) + { + return NULL; + } + else + { + return it->second; + } +} + + + + + +cTeam* cScoreboard::RegisterTeam(const AString & a_Name, const AString & a_DisplayName, + const AString & a_Prefix, const AString & a_Suffix) +{ + cTeam* Team = new cTeam(a_Name, a_DisplayName, a_Prefix, a_Suffix); + + bool Status = m_Teams.insert(NamedTeam(a_Name, Team)).second; + + if (Status) + { + return Team; + } + else + { + delete Team; + return NULL; + } +} + + + + + +bool cScoreboard::RemoveTeam(const AString & a_Name) +{ + TeamMap::iterator it = m_Teams.find(a_Name); + + if (it == m_Teams.end()) + { + return false; + } + + m_Teams.erase(it); + + return true; +} + + + + + +cTeam* cScoreboard::GetTeam(const AString & a_Name) +{ + TeamMap::iterator it = m_Teams.find(a_Name); + + if (it == m_Teams.end()) + { + return NULL; + } + else + { + return it->second; + } +} + + + + + +void cScoreboard::ForEachObjectiveWith(eObjectiveType a_Type, cObjectiveCallback& a_Callback) +{ + for (ObjectiveMap::iterator it = m_Objectives.begin(); it != m_Objectives.end(); ++it) + { + if (it->second->GetType() == a_Type) + { + // Call callback + if (a_Callback.Item(it->second)) + { + return; + } + } + } +} + + + + diff --git a/src/Scoreboard.h b/src/Scoreboard.h new file mode 100644 index 000000000..8ab298a07 --- /dev/null +++ b/src/Scoreboard.h @@ -0,0 +1,207 @@ + +// Scoreboard.h + +// Implementation of a scoreboard that keeps track of specified objectives + + + + + +#pragma once + + + + + +class cPlayer; +class cObjective; + +typedef std::set< cPlayer * > cPlayerSet; +typedef cItemCallback cObjectiveCallback; + + + + + +enum eObjectiveType +{ + E_OBJECTIVE_DUMMY, + + E_OBJECTIVE_DEATH_COUNT, + E_OBJECTIVE_PLAYER_KILL_COUNT, + E_OBJECTIVE_TOTAL_KILL_COUNT, + E_OBJECTIVE_HEALTH, + + E_OBJECTIVE_ACHIEVEMENT, + + E_OBJECTIVE_STAT, + E_OBJECTIVE_STAT_ITEM_CRAFT, + E_OBJECTIVE_STAT_ITEM_USE, + E_OBJECTIVE_STAT_ITEM_BREAK, + + E_OBJECTIVE_STAT_BLOCK_MINE, + E_OBJECTIVE_STAT_ENTITY_KILL, + E_OBJECTIVE_STAT_ENTITY_KILLED_BY +}; + + + + + +enum eDisplaySlot +{ + E_DISPLAY_SLOT_LIST, + E_DISPLAY_SLOT_SIDEBAR, + E_DISPLAY_SLOT_NAME +}; + + + + + +class cObjective +{ +public: + typedef int Score; + +public: + cObjective(eObjectiveType a_Type); + + eObjectiveType GetType(void) const { return m_Type; } + + eDisplaySlot GetDisplaySlot(void) const { return m_Display; } + + void SetDisplaySlot(eDisplaySlot a_Display); + + /// Resets the objective + void Reset(void); + + /// Returns the score of the specified player + Score GetScore(const AString & a_Name) const; + + /// Sets the score of the specified player + void SetScore(const AString & a_Name, Score a_Score); + + /// Resets the score of the specified player + void ResetScore(const AString & a_Name); + + /// Adds a_Delta and returns the new score + Score AddScore(const AString & a_Name, Score a_Delta); + + /// Subtracts a_Delta and returns the new score + Score SubScore(const AString & a_Name, Score a_Delta); + +private: + typedef std::pair TrackedPlayer; + + typedef std::map ScoreMap; + + ScoreMap m_Scores; + + eObjectiveType m_Type; + + eDisplaySlot m_Display; +}; + + + + + +class cTeam +{ +public: + cTeam(const AString & a_Name, const AString & a_DisplayName, + const AString & a_Prefix, const AString & a_Suffix); + + /// Adds a new player to the team + bool AddPlayer(cPlayer * a_Player); + + /// Removes a player from the team + bool RemovePlayer(cPlayer * a_Player); + + /// Removes all registered players + void Reset(void); + + /// Returns the number of registered players + unsigned int GetNumPlayers(void) const; + + bool GetFriendlyFire(void) const { return m_FriendlyFire; } + bool GetCanSeeFriendlyInvisible(void) const { return m_SeeFriendlyInvisible; } + + const AString & GetDisplayName(void) const { return m_Name; } + const AString & GetName(void) const { return m_DisplayName; } + + 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 SetDisplayName(const AString & a_Name); + + void SetPrefix(const AString & a_Prefix); + void SetSuffix(const AString & a_Suffix); + +private: + + bool m_FriendlyFire; + bool m_SeeFriendlyInvisible; + + AString m_DisplayName; + AString m_Name; + + AString m_Prefix; + AString m_Suffix; + + // TODO 2014-01-19 xdot: Potential optimization - vector/list + cPlayerSet m_Players; +}; + + + + + +class cScoreboard +{ +public: + cScoreboard() {} + virtual ~cScoreboard(); + + /// Registers a new scoreboard objective, returns the cObjective instance + cObjective* RegisterObjective(const AString & a_Name, eObjectiveType 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); + + /// Registers a new team, returns the cTeam instance + 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); + + /// Execute callback for each objective with the specified type + void ForEachObjectiveWith(eObjectiveType a_Type, cObjectiveCallback& a_Callback); + +private: + typedef std::pair NamedObjective; + typedef std::pair NamedTeam; + + typedef std::map ObjectiveMap; + typedef std::map TeamMap; + + // TODO 2014-01-19 xdot: Potential optimization - Sort objectives based on type + ObjectiveMap m_Objectives; + + TeamMap m_Teams; +} ; + + + + diff --git a/src/World.h b/src/World.h index 1a7ad0cb1..1dcbac8e4 100644 --- a/src/World.h +++ b/src/World.h @@ -22,6 +22,7 @@ #include "Item.h" #include "Mobs/Monster.h" #include "Entities/ProjectileEntity.h" +#include "Scoreboard.h" @@ -513,6 +514,9 @@ public: /// Returns the name of the world.ini file used by this world const AString & GetIniFileName(void) const {return m_IniFileName; } + + /// Returns the associated scoreboard instance + cScoreboard* GetScoreBoard(void) { return &m_Scoreboard; } // tolua_end @@ -757,6 +761,8 @@ private: sSetBlockList m_FastSetBlockQueue; cChunkGenerator m_Generator; + + cScoreboard m_Scoreboard; /** The callbacks that the ChunkGenerator uses to store new chunks and interface to plugins */ cChunkGeneratorCallbacks m_GeneratorCallbacks; From f321b5d224cb4a6d562cfb32850bf752ddd69f61 Mon Sep 17 00:00:00 2001 From: andrew Date: Sun, 19 Jan 2014 16:02:37 +0200 Subject: [PATCH 2/7] Scoreboard improvements --- src/Entities/Player.cpp | 8 +-- src/Scoreboard.cpp | 79 +++++++++------------------ src/Scoreboard.h | 116 +++++++++++++++++++--------------------- 3 files changed, 83 insertions(+), 120 deletions(-) diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 4f3c6138b..d2fdba909 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -798,7 +798,7 @@ void cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI) if ((m_Team != NULL) && (m_Team == Attacker->m_Team)) { - if (!m_Team->GetFriendlyFire()) + if (!m_Team->AllowsFriendlyFire()) { // Friendly fire is disabled return; @@ -868,7 +868,7 @@ void cPlayer::KilledBy(cEntity * a_Killer) cScoreboard* Scoreboard = m_World->GetScoreBoard(); // Update scoreboard objectives - Scoreboard->ForEachObjectiveWith(E_OBJECTIVE_DEATH_COUNT, IncrementCounter); + Scoreboard->ForEachObjectiveWith(cObjective::E_TYPE_DEATH_COUNT, IncrementCounter); } @@ -953,14 +953,14 @@ void cPlayer::SetTeam(cTeam* a_Team) { if (m_Team) { - m_Team->RemovePlayer(this); + m_Team->RemovePlayer(GetName()); } m_Team = a_Team; if (m_Team) { - m_Team->AddPlayer(this); + m_Team->AddPlayer(GetName()); } } diff --git a/src/Scoreboard.cpp b/src/Scoreboard.cpp index 1d2711ca0..539316356 100644 --- a/src/Scoreboard.cpp +++ b/src/Scoreboard.cpp @@ -11,14 +11,14 @@ -cObjective::cObjective(eObjectiveType a_Type) : m_Type(a_Type) +cObjective::cObjective(cObjective::eType a_Type) : m_Type(a_Type) {} -void cObjective::SetDisplaySlot(eDisplaySlot a_Display) +void cObjective::SetDisplaySlot(cObjective::eDisplaySlot a_Display) { m_Display = a_Display; } @@ -102,8 +102,8 @@ cObjective::Score cObjective::SubScore(const AString & a_Name, cObjective::Score cTeam::cTeam(const AString & a_Name, const AString & a_DisplayName, const AString & a_Prefix, const AString & a_Suffix) - : m_FriendlyFire(true) - , m_SeeFriendlyInvisible(false) + : m_AllowsFriendlyFire(true) + , m_CanSeeFriendlyInvisible(false) , m_Name(a_Name) , m_DisplayName(a_DisplayName) , m_Prefix(a_Prefix) @@ -114,18 +114,18 @@ cTeam::cTeam(const AString & a_Name, const AString & a_DisplayName, -bool cTeam::AddPlayer(cPlayer * a_Player) +bool cTeam::AddPlayer(const AString & a_Name) { - return m_Players.insert(a_Player).second; + return m_Players.insert(a_Name).second; } -bool cTeam::RemovePlayer(cPlayer * a_Player) +bool cTeam::RemovePlayer(const AString & a_Name) { - return m_Players.erase(a_Player) > 0; + return m_Players.erase(a_Name) > 0; } @@ -149,38 +149,13 @@ unsigned int cTeam::GetNumPlayers(void) const -cScoreboard::~cScoreboard() +cObjective* cScoreboard::RegisterObjective(const AString & a_Name, cObjective::eType a_Type) { - for (ObjectiveMap::iterator it = m_Objectives.begin(); it != m_Objectives.end(); ++it) - { - delete it->second; - } + cObjective Objective(a_Type); - for (TeamMap::iterator it = m_Teams.begin(); it != m_Teams.end(); ++it) - { - delete it->second; - } -} + std::pair Status = m_Objectives.insert(NamedObjective(a_Name, Objective)); - - - - -cObjective* cScoreboard::RegisterObjective(const AString & a_Name, eObjectiveType a_Type) -{ - cObjective* Objective = new cObjective(a_Type); - - bool Status = m_Objectives.insert(NamedObjective(a_Name, Objective)).second; - - if (Status) - { - return Objective; - } - else - { - delete Objective; - return NULL; - } + return Status.second ? &Status.first->second : NULL; } @@ -215,7 +190,7 @@ cObjective* cScoreboard::GetObjective(const AString & a_Name) } else { - return it->second; + return &it->second; } } @@ -223,22 +198,16 @@ cObjective* cScoreboard::GetObjective(const AString & a_Name) -cTeam* cScoreboard::RegisterTeam(const AString & a_Name, const AString & a_DisplayName, - const AString & a_Prefix, const AString & a_Suffix) +cTeam* cScoreboard::RegisterTeam( + const AString & a_Name, const AString & a_DisplayName, + const AString & a_Prefix, const AString & a_Suffix +) { - cTeam* Team = new cTeam(a_Name, a_DisplayName, a_Prefix, a_Suffix); + cTeam Team(a_Name, a_DisplayName, a_Prefix, a_Suffix); - bool Status = m_Teams.insert(NamedTeam(a_Name, Team)).second; + std::pair Status = m_Teams.insert(NamedTeam(a_Name, Team)); - if (Status) - { - return Team; - } - else - { - delete Team; - return NULL; - } + return Status.second ? &Status.first->second : NULL; } @@ -273,7 +242,7 @@ cTeam* cScoreboard::GetTeam(const AString & a_Name) } else { - return it->second; + return &it->second; } } @@ -281,14 +250,14 @@ cTeam* cScoreboard::GetTeam(const AString & a_Name) -void cScoreboard::ForEachObjectiveWith(eObjectiveType a_Type, cObjectiveCallback& a_Callback) +void cScoreboard::ForEachObjectiveWith(cObjective::eType a_Type, cObjectiveCallback& a_Callback) { for (ObjectiveMap::iterator it = m_Objectives.begin(); it != m_Objectives.end(); ++it) { - if (it->second->GetType() == a_Type) + if (it->second.GetType() == a_Type) { // Call callback - if (a_Callback.Item(it->second)) + if (a_Callback.Item(&it->second)) { return; } diff --git a/src/Scoreboard.h b/src/Scoreboard.h index 8ab298a07..7993b1333 100644 --- a/src/Scoreboard.h +++ b/src/Scoreboard.h @@ -13,61 +13,51 @@ -class cPlayer; class cObjective; -typedef std::set< cPlayer * > cPlayerSet; typedef cItemCallback cObjectiveCallback; -enum eObjectiveType -{ - E_OBJECTIVE_DUMMY, - - E_OBJECTIVE_DEATH_COUNT, - E_OBJECTIVE_PLAYER_KILL_COUNT, - E_OBJECTIVE_TOTAL_KILL_COUNT, - E_OBJECTIVE_HEALTH, - - E_OBJECTIVE_ACHIEVEMENT, - - E_OBJECTIVE_STAT, - E_OBJECTIVE_STAT_ITEM_CRAFT, - E_OBJECTIVE_STAT_ITEM_USE, - E_OBJECTIVE_STAT_ITEM_BREAK, - - E_OBJECTIVE_STAT_BLOCK_MINE, - E_OBJECTIVE_STAT_ENTITY_KILL, - E_OBJECTIVE_STAT_ENTITY_KILLED_BY -}; - - - - - -enum eDisplaySlot -{ - E_DISPLAY_SLOT_LIST, - E_DISPLAY_SLOT_SIDEBAR, - E_DISPLAY_SLOT_NAME -}; - - - - - class cObjective { public: typedef int Score; -public: - cObjective(eObjectiveType a_Type); + enum eType + { + E_TYPE_DUMMY, - eObjectiveType GetType(void) const { return m_Type; } + E_TYPE_DEATH_COUNT, + E_TYPE_PLAYER_KILL_COUNT, + E_TYPE_TOTAL_KILL_COUNT, + E_TYPE_HEALTH, + + E_TYPE_ACHIEVEMENT, + + E_TYPE_STAT, + E_TYPE_STAT_ITEM_CRAFT, + E_TYPE_STAT_ITEM_USE, + E_TYPE_STAT_ITEM_BREAK, + + E_TYPE_STAT_BLOCK_MINE, + E_TYPE_STAT_ENTITY_KILL, + E_TYPE_STAT_ENTITY_KILLED_BY + }; + + enum eDisplaySlot + { + E_DISPLAY_SLOT_LIST, + E_DISPLAY_SLOT_SIDEBAR, + E_DISPLAY_SLOT_NAME + }; + +public: + cObjective(eType a_Type); + + eType GetType(void) const { return m_Type; } eDisplaySlot GetDisplaySlot(void) const { return m_Display; } @@ -98,7 +88,7 @@ private: ScoreMap m_Scores; - eObjectiveType m_Type; + eType m_Type; eDisplaySlot m_Display; }; @@ -110,14 +100,17 @@ private: class cTeam { public: - cTeam(const AString & a_Name, const AString & a_DisplayName, - const AString & a_Prefix, const AString & a_Suffix); + + cTeam( + const AString & a_Name, const AString & a_DisplayName, + const AString & a_Prefix, const AString & a_Suffix + ); /// Adds a new player to the team - bool AddPlayer(cPlayer * a_Player); + bool AddPlayer(const AString & a_Name); /// Removes a player from the team - bool RemovePlayer(cPlayer * a_Player); + bool RemovePlayer(const AString & a_Name); /// Removes all registered players void Reset(void); @@ -125,10 +118,10 @@ public: /// Returns the number of registered players unsigned int GetNumPlayers(void) const; - bool GetFriendlyFire(void) const { return m_FriendlyFire; } - bool GetCanSeeFriendlyInvisible(void) const { return m_SeeFriendlyInvisible; } + bool AllowsFriendlyFire(void) const { return m_AllowsFriendlyFire; } + bool CanSeeFriendlyInvisible(void) const { return m_CanSeeFriendlyInvisible; } - const AString & GetDisplayName(void) const { return m_Name; } + const AString & GetDisplayName(void) const { return m_DisplayName; } const AString & GetName(void) const { return m_DisplayName; } const AString & GetPrefix(void) const { return m_Prefix; } @@ -144,8 +137,8 @@ public: private: - bool m_FriendlyFire; - bool m_SeeFriendlyInvisible; + bool m_AllowsFriendlyFire; + bool m_CanSeeFriendlyInvisible; AString m_DisplayName; AString m_Name; @@ -154,7 +147,9 @@ private: AString m_Suffix; // TODO 2014-01-19 xdot: Potential optimization - vector/list - cPlayerSet m_Players; + typedef std::set PlayerNameSet; + + PlayerNameSet m_Players; }; @@ -165,10 +160,9 @@ class cScoreboard { public: cScoreboard() {} - virtual ~cScoreboard(); - /// Registers a new scoreboard objective, returns the cObjective instance - cObjective* RegisterObjective(const AString & a_Name, eObjectiveType a_Type); + /// Registers a new scoreboard objective, returns the cObjective instance, NULL on name collision + cObjective* RegisterObjective(const AString & a_Name, cObjective::eType a_Type); /// Removes a registered objective, returns true if operation was successful bool RemoveObjective(const AString & a_Name); @@ -176,7 +170,7 @@ public: /// Retrieves the objective with the specified name, NULL if not found cObjective* GetObjective(const AString & a_Name); - /// Registers a new team, returns the cTeam instance + /// 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); @@ -187,14 +181,14 @@ public: cTeam* GetTeam(const AString & a_Name); /// Execute callback for each objective with the specified type - void ForEachObjectiveWith(eObjectiveType a_Type, cObjectiveCallback& a_Callback); + void ForEachObjectiveWith(cObjective::eType a_Type, cObjectiveCallback& a_Callback); private: - typedef std::pair NamedObjective; - typedef std::pair NamedTeam; + typedef std::pair NamedObjective; + typedef std::pair NamedTeam; - typedef std::map ObjectiveMap; - typedef std::map TeamMap; + typedef std::map ObjectiveMap; + typedef std::map TeamMap; // TODO 2014-01-19 xdot: Potential optimization - Sort objectives based on type ObjectiveMap m_Objectives; From 7728f4bcbee7fa61f005c7b972685deb4bf04f2a Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 20 Jan 2014 16:10:39 +0200 Subject: [PATCH 3/7] Scoreboard deserialization --- src/Entities/Player.cpp | 22 +- src/Entities/Player.h | 7 +- src/Scoreboard.cpp | 176 ++++++++++-- src/Scoreboard.h | 87 ++++-- src/WorldStorage/ScoreboardSerializer.cpp | 317 ++++++++++++++++++++++ src/WorldStorage/ScoreboardSerializer.h | 48 ++++ src/WorldStorage/WSSAnvil.cpp | 2 +- 7 files changed, 605 insertions(+), 54 deletions(-) create mode 100644 src/WorldStorage/ScoreboardSerializer.cpp create mode 100644 src/WorldStorage/ScoreboardSerializer.h 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; } From ff2302ebd53453242175683587b19ae5de5d1aed Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 20 Jan 2014 16:45:40 +0200 Subject: [PATCH 4/7] Scoreboard serialization --- src/Scoreboard.cpp | 11 +-- src/Scoreboard.h | 18 +++-- src/WorldStorage/ScoreboardSerializer.cpp | 81 +++++++++++++++++++++-- 3 files changed, 94 insertions(+), 16 deletions(-) diff --git a/src/Scoreboard.cpp b/src/Scoreboard.cpp index 864837d3d..3ddf146a6 100644 --- a/src/Scoreboard.cpp +++ b/src/Scoreboard.cpp @@ -72,7 +72,10 @@ cObjective::eType cObjective::StringToType(const AString & a_Name) -cObjective::cObjective(const AString & a_DisplayName, cObjective::eType a_Type) : m_DisplayName(a_DisplayName), m_Type(a_Type) +cObjective::cObjective(const AString & a_Name, const AString & a_DisplayName, cObjective::eType a_Type) + : m_DisplayName(a_DisplayName) + , m_Name(a_Name) + , m_Type(a_Type) {} @@ -90,7 +93,7 @@ void cObjective::Reset(void) cObjective::Score cObjective::GetScore(const AString & a_Name) const { - ScoreMap::const_iterator it = m_Scores.find(a_Name); + cScoreMap::const_iterator it = m_Scores.find(a_Name); if (it == m_Scores.end()) { @@ -226,7 +229,7 @@ cScoreboard::cScoreboard() cObjective* cScoreboard::RegisterObjective(const AString & a_Name, const AString & a_DisplayName, cObjective::eType a_Type) { - cObjective Objective(a_DisplayName, a_Type); + cObjective Objective(a_Name, a_DisplayName, a_Type); std::pair Status = m_Objectives.insert(cNamedObjective(a_Name, Objective)); @@ -355,7 +358,7 @@ void cScoreboard::SetDisplay(const AString & a_Objective, eDisplaySlot a_Slot) -cObjective* cScoreboard::GetObjectiveIn(eDisplaySlot a_Slot) +cObjective * cScoreboard::GetObjectiveIn(eDisplaySlot a_Slot) { ASSERT(a_Slot < E_DISPLAY_SLOT_COUNT); diff --git a/src/Scoreboard.h b/src/Scoreboard.h index f7285a9cf..2ce614de7 100644 --- a/src/Scoreboard.h +++ b/src/Scoreboard.h @@ -54,10 +54,11 @@ public: public: - cObjective(const AString & a_DisplayName, eType a_Type); + cObjective(const AString & a_Name, const AString & a_DisplayName, eType a_Type); eType GetType(void) const { return m_Type; } + const AString & GetName(void) const { return m_Name; } const AString & GetDisplayName(void) const { return m_DisplayName; } /// Resets the objective @@ -80,16 +81,19 @@ public: private: - typedef std::pair TrackedPlayer; + typedef std::pair cTrackedPlayer; - typedef std::map ScoreMap; + typedef std::map cScoreMap; - ScoreMap m_Scores; + cScoreMap m_Scores; AString m_DisplayName; + AString m_Name; eType m_Type; + friend class cScoreboardSerializer; + }; @@ -152,6 +156,8 @@ private: cPlayerNameSet m_Players; + friend class cScoreboardSerializer; + }; @@ -198,7 +204,7 @@ public: void SetDisplay(const AString & a_Objective, eDisplaySlot a_Slot); - cObjective* GetObjectiveIn(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); @@ -223,6 +229,8 @@ private: cObjective* m_Display[E_DISPLAY_SLOT_COUNT]; + friend class cScoreboardSerializer; + } ; diff --git a/src/WorldStorage/ScoreboardSerializer.cpp b/src/WorldStorage/ScoreboardSerializer.cpp index c2f13a092..bcac50bb6 100644 --- a/src/WorldStorage/ScoreboardSerializer.cpp +++ b/src/WorldStorage/ScoreboardSerializer.cpp @@ -109,21 +109,88 @@ bool cScoreboardSerializer::Save(void) void cScoreboardSerializer::SaveScoreboardToNBT(cFastNBTWriter & a_Writer) { a_Writer.BeginCompound("Data"); - a_Writer.BeginList("Objectives", TAG_Compound); + a_Writer.BeginList("Objectives", TAG_Compound); + + for (cScoreboard::cObjectiveMap::const_iterator it = m_ScoreBoard->m_Objectives.begin(); it != m_ScoreBoard->m_Objectives.end(); ++it) + { + const cObjective & Objective = it->second; + + a_Writer.BeginCompound(""); + + a_Writer.AddString("CriteriaName", cObjective::TypeToString(Objective.GetType())); + + a_Writer.AddString("DisplayName", Objective.GetDisplayName()); + a_Writer.AddString("Name", it->first); + + a_Writer.EndCompound(); + } + + a_Writer.EndList(); + + a_Writer.BeginList("PlayerScores", TAG_Compound); + + for (cScoreboard::cObjectiveMap::const_iterator it = m_ScoreBoard->m_Objectives.begin(); it != m_ScoreBoard->m_Objectives.end(); ++it) + { + const cObjective & Objective = it->second; + + for (cObjective::cScoreMap::const_iterator it2 = Objective.m_Scores.begin(); it2 != Objective.m_Scores.end(); ++it2) + { + a_Writer.BeginCompound(""); + + a_Writer.AddInt("Score", it2->second); + + a_Writer.AddString("Name", it2->first); + a_Writer.AddString("Objective", it->first); + + a_Writer.EndCompound(); + } + } + + a_Writer.EndList(); + + a_Writer.BeginList("Teams", TAG_Compound); + + for (cScoreboard::cTeamMap::const_iterator it = m_ScoreBoard->m_Teams.begin(); it != m_ScoreBoard->m_Teams.end(); ++it) + { + const cTeam & Team = it->second; + + a_Writer.BeginCompound(""); + + a_Writer.AddByte("AllowFriendlyFire", Team.AllowsFriendlyFire() ? 1 : 0); + a_Writer.AddByte("SeeFriendlyInvisibles", Team.CanSeeFriendlyInvisible() ? 1 : 0); + + a_Writer.AddString("DisplayName", Team.GetDisplayName()); + a_Writer.AddString("Name", it->first); + + a_Writer.AddString("Prefix", Team.GetPrefix()); + a_Writer.AddString("Suffix", Team.GetSuffix()); + + a_Writer.BeginList("Players", TAG_String); + + for (cTeam::cPlayerNameSet::const_iterator it2 = Team.m_Players.begin(); it2 != Team.m_Players.end(); ++it2) + { + a_Writer.AddString("", *it2); + } a_Writer.EndList(); - a_Writer.BeginList("PlayerScores", TAG_Compound); + a_Writer.EndCompound(); + } - a_Writer.EndList(); - - a_Writer.BeginList("Teams", TAG_Compound); - - a_Writer.EndList(); + a_Writer.EndList(); a_Writer.EndCompound(); a_Writer.BeginCompound("DisplaySlots"); + cObjective * Objective = m_ScoreBoard->GetObjectiveIn(cScoreboard::E_DISPLAY_SLOT_LIST); + a_Writer.AddString("slot_0", (Objective == NULL) ? "" : Objective->GetName()); + + Objective = m_ScoreBoard->GetObjectiveIn(cScoreboard::E_DISPLAY_SLOT_SIDEBAR); + a_Writer.AddString("slot_1", (Objective == NULL) ? "" : Objective->GetName()); + + Objective = m_ScoreBoard->GetObjectiveIn(cScoreboard::E_DISPLAY_SLOT_NAME); + a_Writer.AddString("slot_2", (Objective == NULL) ? "" : Objective->GetName()); + a_Writer.EndCompound(); } From aa61f55b743a8ecf3cd8e1f99e1d9a0308f6d014 Mon Sep 17 00:00:00 2001 From: andrew Date: Tue, 21 Jan 2014 15:58:17 +0200 Subject: [PATCH 5/7] Scoreboard protocol support --- src/ClientHandle.cpp | 30 +++++++++++ src/ClientHandle.h | 4 ++ src/Entities/Player.cpp | 17 ++++--- src/Protocol/Protocol.h | 4 ++ src/Protocol/Protocol125.h | 7 ++- src/Protocol/Protocol15x.cpp | 54 +++++++++++++++++++- src/Protocol/Protocol15x.h | 3 ++ src/Protocol/Protocol17x.cpp | 40 +++++++++++++++ src/Protocol/Protocol17x.h | 3 ++ src/Protocol/ProtocolRecognizer.cpp | 32 +++++++++++- src/Protocol/ProtocolRecognizer.h | 3 ++ src/Scoreboard.cpp | 66 ++++++++++++++++++++++--- src/Scoreboard.h | 13 ++++- src/Server.cpp | 2 +- src/World.cpp | 57 ++++++++++++++++++++- src/World.h | 5 +- src/WorldStorage/ScoreboardSerializer.h | 4 ++ 17 files changed, 321 insertions(+), 23 deletions(-) diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index faf583fbb..30d1bdaa4 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -267,6 +267,9 @@ void cClientHandle::Authenticate(void) m_Player->Initialize(World); m_State = csAuthenticated; + // Query player team + m_Player->UpdateTeam(); + cRoot::Get()->GetPluginManager()->CallHookPlayerSpawned(*m_Player); } @@ -2105,6 +2108,33 @@ void cClientHandle::SendExperienceOrb(const cExpOrb & a_ExpOrb) +void cClientHandle::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) +{ + m_Protocol->SendScoreboardObjective(a_Name, a_DisplayName, a_Mode); +} + + + + + +void cClientHandle::SendScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) +{ + m_Protocol->SendScoreUpdate(a_Objective, a_Player, a_Score, a_Mode); +} + + + + + +void cClientHandle::SendDisplayObjective(const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) +{ + m_Protocol->SendDisplayObjective(a_Objective, a_Display); +} + + + + + void cClientHandle::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) { m_Protocol->SendSoundEffect(a_SoundName, a_SrcX, a_SrcY, a_SrcZ, a_Volume, a_Pitch); diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 373ca9e2e..636934f6f 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -16,6 +16,7 @@ #include "OSSupport/SocketThreads.h" #include "ChunkDef.h" #include "ByteBuffer.h" +#include "Scoreboard.h" @@ -125,6 +126,9 @@ public: void SendRespawn (void); void SendExperience (void); void SendExperienceOrb (const cExpOrb & a_ExpOrb); + void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode); + void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode); + void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display); void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch); // a_Src coords are Block * 8 void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data); void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock); diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 285aefd25..c6b24a465 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -111,8 +111,6 @@ 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); } @@ -867,10 +865,10 @@ void cPlayer::KilledBy(cEntity * a_Killer) } } IncrementCounter (GetName()); - cScoreboard* Scoreboard = m_World->GetScoreBoard(); + cScoreboard & Scoreboard = m_World->GetScoreBoard(); // Update scoreboard objectives - Scoreboard->ForEachObjectiveWith(cObjective::E_TYPE_DEATH_COUNT, IncrementCounter); + Scoreboard.ForEachObjectiveWith(cObjective::E_TYPE_DEATH_COUNT, IncrementCounter); } @@ -977,9 +975,16 @@ void cPlayer::SetTeam(cTeam * a_Team) cTeam * cPlayer::UpdateTeam(void) { - cScoreboard * Scoreboard = m_World->GetScoreBoard(); + if (m_World == NULL) + { + SetTeam(NULL); + } + else + { + cScoreboard & Scoreboard = m_World->GetScoreBoard(); - m_Team = Scoreboard->QueryPlayerTeam(GetName()); + SetTeam(Scoreboard.QueryPlayerTeam(GetName())); + } return m_Team; } diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h index 3293da32c..0a213f476 100644 --- a/src/Protocol/Protocol.h +++ b/src/Protocol/Protocol.h @@ -12,6 +12,7 @@ #include "../Defines.h" #include "../Endianness.h" +#include "../Scoreboard.h" @@ -92,6 +93,9 @@ public: virtual void SendRespawn (void) = 0; virtual void SendExperience (void) = 0; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) = 0; + virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) = 0; + virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) = 0; + virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) = 0; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) = 0; // a_Src coords are Block * 8 virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) = 0; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) = 0; diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h index d0e5c9428..fb08fb120 100644 --- a/src/Protocol/Protocol125.h +++ b/src/Protocol/Protocol125.h @@ -68,6 +68,9 @@ public: virtual void SendRespawn (void) override; virtual void SendExperience (void) override; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override; + virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override {} // This protocol doesn't support such message + virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override {} // This protocol doesn't support such message + virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override {} // This protocol doesn't support such message virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8 virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override; @@ -82,8 +85,8 @@ public: virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override; virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) override; virtual void SendWeather (eWeather a_Weather) override; - virtual void SendWholeInventory (const cWindow & a_Window) override; - virtual void SendWindowClose (const cWindow & a_Window) override; + virtual void SendWholeInventory (const cWindow & a_Window) override; + virtual void SendWindowClose (const cWindow & a_Window) override; virtual void SendWindowOpen (const cWindow & a_Window) override; virtual void SendWindowProperty (const cWindow & a_Window, short a_Property, short a_Value) override; diff --git a/src/Protocol/Protocol15x.cpp b/src/Protocol/Protocol15x.cpp index 0f1e59f10..c33aec7d5 100644 --- a/src/Protocol/Protocol15x.cpp +++ b/src/Protocol/Protocol15x.cpp @@ -35,8 +35,11 @@ Implements the 1.5.x protocol classes: enum { - PACKET_WINDOW_OPEN = 0x64, - PACKET_PARTICLE_EFFECT = 0x3F, + PACKET_WINDOW_OPEN = 0x64, + PACKET_PARTICLE_EFFECT = 0x3F, + PACKET_SCOREBOARD_OBJECTIVE = 0x3B, + PACKET_SCORE_UPDATE = 0x3C, + PACKET_DISPLAY_OBJECTIVE = 0x3D } ; @@ -97,6 +100,53 @@ void cProtocol150::SendParticleEffect(const AString & a_ParticleName, float a_Sr +void cProtocol150::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_SCOREBOARD_OBJECTIVE); + WriteString(a_Name); + WriteString(a_DisplayName); + WriteByte(a_Mode); + Flush(); +} + + + + + +void cProtocol150::SendScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_SCORE_UPDATE); + WriteString(a_Player); + WriteByte(a_Mode); + + if (a_Mode != 1) + { + WriteString(a_Objective); + WriteInt((int) a_Score); + } + + Flush(); +} + + + + + +void cProtocol150::SendDisplayObjective(const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_DISPLAY_OBJECTIVE); + WriteByte((int) a_Display); + WriteString(a_Objective); + Flush(); +} + + + + + int cProtocol150::ParseWindowClick(void) { HANDLE_PACKET_READ(ReadChar, char, WindowID); diff --git a/src/Protocol/Protocol15x.h b/src/Protocol/Protocol15x.h index 0074b3a83..0d171a67c 100644 --- a/src/Protocol/Protocol15x.h +++ b/src/Protocol/Protocol15x.h @@ -30,6 +30,9 @@ public: virtual void SendWindowOpen (const cWindow & a_Window) override; virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) override; + virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override; + virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override; + virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override; virtual int ParseWindowClick(void); } ; diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 5b3a79555..d5ed1a0aa 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -705,6 +705,46 @@ void cProtocol172::SendExperienceOrb(const cExpOrb & a_ExpOrb) +void cProtocol172::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) +{ + cPacketizer Pkt(*this, 0x3b); + Pkt.WriteString(a_Name); + Pkt.WriteString(a_DisplayName); + Pkt.WriteByte(a_Mode); +} + + + + + +void cProtocol172::SendScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) +{ + cPacketizer Pkt(*this, 0x3c); + Pkt.WriteString(a_Player); + Pkt.WriteByte(a_Mode); + + if (a_Mode != 1) + { + Pkt.WriteString(a_Objective); + Pkt.WriteInt((int) a_Score); + } +} + + + + + +void cProtocol172::SendDisplayObjective(const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) +{ + cPacketizer Pkt(*this, 0x3d); + Pkt.WriteByte((int) a_Display); + Pkt.WriteString(a_Objective); +} + + + + + void cProtocol172::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) // a_Src coords are Block * 8 { cPacketizer Pkt(*this, 0x29); // Sound Effect packet diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h index 07dba834b..bbbf820a6 100644 --- a/src/Protocol/Protocol17x.h +++ b/src/Protocol/Protocol17x.h @@ -92,6 +92,9 @@ public: virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8 virtual void SendExperience (void) override; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override; + virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override; + virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override; + virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override; virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override; virtual void SendSpawnMob (const cMonster & a_Mob) override; diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index a21f4f042..04db2a995 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -526,6 +526,36 @@ void cProtocolRecognizer::SendExperienceOrb(const cExpOrb & a_ExpOrb) +void cProtocolRecognizer::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendScoreboardObjective(a_Name, a_DisplayName, a_Mode); +} + + + + + +void cProtocolRecognizer::SendScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendScoreUpdate(a_Objective, a_Player, a_Score, a_Mode); +} + + + + + +void cProtocolRecognizer::SendDisplayObjective(const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendDisplayObjective(a_Objective, a_Display); +} + + + + + void cProtocolRecognizer::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) { ASSERT(m_Protocol != NULL); @@ -797,7 +827,7 @@ bool cProtocolRecognizer::TryRecognizeLengthlessProtocol(void) } switch (ch) { - case PROTO_VERSION_1_3_2: + case PROTO_VERSION_1_3_2: { m_Protocol = new cProtocol132(m_Client); return true; diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h index e94f4cde8..0b811f4c6 100644 --- a/src/Protocol/ProtocolRecognizer.h +++ b/src/Protocol/ProtocolRecognizer.h @@ -103,6 +103,9 @@ public: virtual void SendRespawn (void) override; virtual void SendExperience (void) override; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override; + virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override; + virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override; + virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override; diff --git a/src/Scoreboard.cpp b/src/Scoreboard.cpp index 3ddf146a6..7fa1eab99 100644 --- a/src/Scoreboard.cpp +++ b/src/Scoreboard.cpp @@ -6,6 +6,7 @@ #include "Globals.h" #include "Scoreboard.h" +#include "World.h" @@ -72,11 +73,13 @@ cObjective::eType cObjective::StringToType(const AString & a_Name) -cObjective::cObjective(const AString & a_Name, const AString & a_DisplayName, cObjective::eType a_Type) +cObjective::cObjective(const AString & a_Name, const AString & a_DisplayName, cObjective::eType a_Type, cWorld * a_World) : m_DisplayName(a_DisplayName) , m_Name(a_Name) , m_Type(a_Type) -{} + , m_World(a_World) +{ +} @@ -84,6 +87,11 @@ cObjective::cObjective(const AString & a_Name, const AString & a_DisplayName, cO void cObjective::Reset(void) { + for (cScoreMap::iterator it = m_Scores.begin(); it != m_Scores.end(); ++it) + { + m_World->BroadcastScoreUpdate(m_Name, it->first, 0, 1); + } + m_Scores.clear(); } @@ -112,6 +120,8 @@ cObjective::Score cObjective::GetScore(const AString & a_Name) const void cObjective::SetScore(const AString & a_Name, cObjective::Score a_Score) { m_Scores[a_Name] = a_Score; + + m_World->BroadcastScoreUpdate(m_Name, a_Name, a_Score, 0); } @@ -121,6 +131,8 @@ void cObjective::SetScore(const AString & a_Name, cObjective::Score a_Score) void cObjective::ResetScore(const AString & a_Name) { m_Scores.erase(a_Name); + + m_World->BroadcastScoreUpdate(m_Name, a_Name, 0, 1); } @@ -132,7 +144,7 @@ cObjective::Score cObjective::AddScore(const AString & a_Name, cObjective::Score // TODO 2014-01-19 xdot: Potential optimization - Reuse iterator Score NewScore = m_Scores[a_Name] + a_Delta; - m_Scores[a_Name] = NewScore; + SetScore(a_Name, NewScore); return NewScore; } @@ -146,7 +158,7 @@ cObjective::Score cObjective::SubScore(const AString & a_Name, cObjective::Score // TODO 2014-01-19 xdot: Potential optimization - Reuse iterator Score NewScore = m_Scores[a_Name] - a_Delta; - m_Scores[a_Name] = NewScore; + SetScore(a_Name, NewScore); return NewScore; } @@ -155,6 +167,17 @@ cObjective::Score cObjective::SubScore(const AString & a_Name, cObjective::Score +void cObjective::SetDisplayName(const AString & a_Name) +{ + m_DisplayName = a_Name; + + m_World->BroadcastScoreboardObjective(m_Name, m_DisplayName, 2); +} + + + + + cTeam::cTeam(const AString & a_Name, const AString & a_DisplayName, const AString & a_Prefix, const AString & a_Suffix) : m_AllowsFriendlyFire(true) @@ -215,7 +238,7 @@ unsigned int cTeam::GetNumPlayers(void) const -cScoreboard::cScoreboard() +cScoreboard::cScoreboard(cWorld * a_World) : m_World(a_World) { for (int i = 0; i < (int) E_DISPLAY_SLOT_COUNT; ++i) { @@ -229,11 +252,21 @@ cScoreboard::cScoreboard() cObjective* cScoreboard::RegisterObjective(const AString & a_Name, const AString & a_DisplayName, cObjective::eType a_Type) { - cObjective Objective(a_Name, a_DisplayName, a_Type); + cObjective Objective(a_Name, a_DisplayName, a_Type, m_World); std::pair Status = m_Objectives.insert(cNamedObjective(a_Name, Objective)); - return Status.second ? &Status.first->second : NULL; + if (Status.second) + { + ASSERT(m_World != NULL); + m_World->BroadcastScoreboardObjective(a_Name, a_DisplayName, 0); + + return &Status.first->second; + } + else + { + return NULL; + } } @@ -242,6 +275,8 @@ cObjective* cScoreboard::RegisterObjective(const AString & a_Name, const AString bool cScoreboard::RemoveObjective(const AString & a_Name) { + cCSLock Lock(m_CSObjectives); + cObjectiveMap::iterator it = m_Objectives.find(a_Name); if (it == m_Objectives.end()) @@ -251,6 +286,9 @@ bool cScoreboard::RemoveObjective(const AString & a_Name) m_Objectives.erase(it); + ASSERT(m_World != NULL); + m_World->BroadcastScoreboardObjective(it->second.GetName(), it->second.GetDisplayName(), 1); + return true; } @@ -260,6 +298,8 @@ bool cScoreboard::RemoveObjective(const AString & a_Name) cObjective * cScoreboard::GetObjective(const AString & a_Name) { + cCSLock Lock(m_CSObjectives); + cObjectiveMap::iterator it = m_Objectives.find(a_Name); if (it == m_Objectives.end()) @@ -294,6 +334,8 @@ cTeam * cScoreboard::RegisterTeam( bool cScoreboard::RemoveTeam(const AString & a_Name) { + cCSLock Lock(m_CSTeams); + cTeamMap::iterator it = m_Teams.find(a_Name); if (it == m_Teams.end()) @@ -312,6 +354,8 @@ bool cScoreboard::RemoveTeam(const AString & a_Name) cTeam * cScoreboard::GetTeam(const AString & a_Name) { + cCSLock Lock(m_CSTeams); + cTeamMap::iterator it = m_Teams.find(a_Name); if (it == m_Teams.end()) @@ -330,6 +374,8 @@ cTeam * cScoreboard::GetTeam(const AString & a_Name) cTeam * cScoreboard::QueryPlayerTeam(const AString & a_Name) { + cCSLock Lock(m_CSTeams); + for (cTeamMap::iterator it = m_Teams.begin(); it != m_Teams.end(); ++it) { if (it->second.HasPlayer(a_Name)) @@ -352,6 +398,10 @@ void cScoreboard::SetDisplay(const AString & a_Objective, eDisplaySlot a_Slot) cObjective * Objective = GetObjective(a_Objective); m_Display[a_Slot] = Objective; + + ASSERT(m_World != NULL); + m_World->BroadcastDisplayObjective(Objective ? a_Objective : "", a_Slot); + } @@ -371,6 +421,8 @@ cObjective * cScoreboard::GetObjectiveIn(eDisplaySlot a_Slot) void cScoreboard::ForEachObjectiveWith(cObjective::eType a_Type, cObjectiveCallback& a_Callback) { + cCSLock Lock(m_CSObjectives); + for (cObjectiveMap::iterator it = m_Objectives.begin(); it != m_Objectives.end(); ++it) { if (it->second.GetType() == a_Type) diff --git a/src/Scoreboard.h b/src/Scoreboard.h index 2ce614de7..b92642a9a 100644 --- a/src/Scoreboard.h +++ b/src/Scoreboard.h @@ -14,6 +14,7 @@ class cObjective; +class cWorld; typedef cItemCallback cObjectiveCallback; @@ -54,7 +55,7 @@ public: public: - cObjective(const AString & a_Name, const AString & a_DisplayName, eType a_Type); + cObjective(const AString & a_Name, const AString & a_DisplayName, eType a_Type, cWorld * a_World); eType GetType(void) const { return m_Type; } @@ -79,6 +80,8 @@ public: /// Subtracts a_Delta and returns the new score Score SubScore(const AString & a_Name, Score a_Delta); + void SetDisplayName(const AString & a_Name); + private: typedef std::pair cTrackedPlayer; @@ -92,6 +95,8 @@ private: eType m_Type; + cWorld * m_World; + friend class cScoreboardSerializer; }; @@ -180,7 +185,7 @@ public: public: - cScoreboard(); + cScoreboard(cWorld * a_World); /// Registers a new scoreboard objective, returns the cObjective instance, NULL on name collision cObjective * RegisterObjective(const AString & a_Name, const AString & a_DisplayName, cObjective::eType a_Type); @@ -223,10 +228,14 @@ private: typedef std::map cTeamMap; // TODO 2014-01-19 xdot: Potential optimization - Sort objectives based on type + cCriticalSection m_CSObjectives; cObjectiveMap m_Objectives; + cCriticalSection m_CSTeams; cTeamMap m_Teams; + cWorld * m_World; + cObjective* m_Display[E_DISPLAY_SLOT_COUNT]; friend class cScoreboardSerializer; diff --git a/src/Server.cpp b/src/Server.cpp index 5280270b9..eb76fcaeb 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -501,7 +501,7 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac } } #endif - + if (cPluginManager::Get()->ExecuteConsoleCommand(split, a_Output)) { a_Output.Finished(); diff --git a/src/World.cpp b/src/World.cpp index 8e7b6171c..fb20e2242 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -242,7 +242,8 @@ cWorld::cWorld(const AString & a_WorldName) : m_Weather(eWeather_Sunny), m_WeatherInterval(24000), // Guaranteed 1 day of sunshine at server start :) m_GeneratorCallbacks(*this), - m_TickThread(*this) + m_TickThread(*this), + m_Scoreboard(this) { LOGD("cWorld::cWorld(\"%s\")", a_WorldName.c_str()); @@ -1982,6 +1983,60 @@ void cWorld::BroadcastRemoveEntityEffect(const cEntity & a_Entity, int a_EffectI +void cWorld::BroadcastScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) +{ + cCSLock Lock(m_CSPlayers); + for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + { + cClientHandle * ch = (*itr)->GetClientHandle(); + if ((ch == NULL) || !ch->IsLoggedIn() || ch->IsDestroyed()) + { + continue; + } + ch->SendScoreboardObjective(a_Name, a_DisplayName, a_Mode); + } +} + + + + + +void cWorld::BroadcastScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) +{ + cCSLock Lock(m_CSPlayers); + for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + { + cClientHandle * ch = (*itr)->GetClientHandle(); + if ((ch == NULL) || !ch->IsLoggedIn() || ch->IsDestroyed()) + { + continue; + } + ch->SendScoreUpdate(a_Objective, a_Player, a_Score, a_Mode); + } +} + + + + + +void cWorld::BroadcastDisplayObjective(const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) +{ + cCSLock Lock(m_CSPlayers); + for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + { + cClientHandle * ch = (*itr)->GetClientHandle(); + if ((ch == NULL) || !ch->IsLoggedIn() || ch->IsDestroyed()) + { + continue; + } + ch->SendDisplayObjective(a_Objective, a_Display); + } +} + + + + + void cWorld::BroadcastSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude) { m_ChunkMap->BroadcastSoundEffect(a_SoundName, a_SrcX, a_SrcY, a_SrcZ, a_Volume, a_Pitch, a_Exclude); diff --git a/src/World.h b/src/World.h index 1dcbac8e4..51c3af8cb 100644 --- a/src/World.h +++ b/src/World.h @@ -179,6 +179,9 @@ public: void BroadcastParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount, cClientHandle * a_Exclude = NULL); void BroadcastPlayerListItem (const cPlayer & a_Player, bool a_IsOnline, const cClientHandle * a_Exclude = NULL); void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = NULL); + void BroadcastScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode); + void BroadcastScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode); + void BroadcastDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display); void BroadcastSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // tolua_export a_Src coords are Block * 8 void BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL); // tolua_export void BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); @@ -516,7 +519,7 @@ public: const AString & GetIniFileName(void) const {return m_IniFileName; } /// Returns the associated scoreboard instance - cScoreboard* GetScoreBoard(void) { return &m_Scoreboard; } + cScoreboard & GetScoreBoard(void) { return m_Scoreboard; } // tolua_end diff --git a/src/WorldStorage/ScoreboardSerializer.h b/src/WorldStorage/ScoreboardSerializer.h index 2a4e0767e..048fa3ab4 100644 --- a/src/WorldStorage/ScoreboardSerializer.h +++ b/src/WorldStorage/ScoreboardSerializer.h @@ -24,6 +24,7 @@ class cScoreboard; class cScoreboardSerializer { public: + cScoreboardSerializer(const AString & a_WorldName, cScoreboard* a_ScoreBoard); /// Try to load the scoreboard @@ -32,6 +33,7 @@ public: /// Try to save the scoreboard bool Save(void); + private: void SaveScoreboardToNBT(cFastNBTWriter & a_Writer); @@ -41,6 +43,8 @@ private: cScoreboard* m_ScoreBoard; AString m_Path; + + } ; From fa4750f015f1fed0937ba9fe80fc183c27d9e929 Mon Sep 17 00:00:00 2001 From: andrew Date: Tue, 21 Jan 2014 19:43:13 +0200 Subject: [PATCH 6/7] Scoreboard SendTo() --- src/ClientHandle.cpp | 3 ++ src/Protocol/Protocol17x.cpp | 6 ++-- src/Scoreboard.cpp | 54 ++++++++++++++++++++++++++++++++++-- src/Scoreboard.h | 17 ++++++++++++ 4 files changed, 74 insertions(+), 6 deletions(-) diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 30d1bdaa4..b06dbc84a 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -270,6 +270,9 @@ void cClientHandle::Authenticate(void) // Query player team m_Player->UpdateTeam(); + // Send scoreboard data + World->GetScoreBoard().SendTo(*this); + cRoot::Get()->GetPluginManager()->CallHookPlayerSpawned(*m_Player); } diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index d5ed1a0aa..926be6027 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -707,7 +707,7 @@ void cProtocol172::SendExperienceOrb(const cExpOrb & a_ExpOrb) void cProtocol172::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) { - cPacketizer Pkt(*this, 0x3b); + cPacketizer Pkt(*this, 0x3B); Pkt.WriteString(a_Name); Pkt.WriteString(a_DisplayName); Pkt.WriteByte(a_Mode); @@ -719,7 +719,7 @@ void cProtocol172::SendScoreboardObjective(const AString & a_Name, const AString void cProtocol172::SendScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) { - cPacketizer Pkt(*this, 0x3c); + cPacketizer Pkt(*this, 0x3C); Pkt.WriteString(a_Player); Pkt.WriteByte(a_Mode); @@ -736,7 +736,7 @@ void cProtocol172::SendScoreUpdate(const AString & a_Objective, const AString & void cProtocol172::SendDisplayObjective(const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) { - cPacketizer Pkt(*this, 0x3d); + cPacketizer Pkt(*this, 0x3D); Pkt.WriteByte((int) a_Display); Pkt.WriteString(a_Objective); } diff --git a/src/Scoreboard.cpp b/src/Scoreboard.cpp index 7fa1eab99..e6812d3d7 100644 --- a/src/Scoreboard.cpp +++ b/src/Scoreboard.cpp @@ -7,6 +7,7 @@ #include "Scoreboard.h" #include "World.h" +#include "ClientHandle.h" @@ -178,6 +179,20 @@ void cObjective::SetDisplayName(const AString & a_Name) +void cObjective::SendTo(cClientHandle & a_Client) +{ + a_Client.SendScoreboardObjective(m_Name, m_DisplayName, 0); + + for (cScoreMap::const_iterator it = m_Scores.begin(); it != m_Scores.end(); ++it) + { + a_Client.SendScoreUpdate(m_Name, it->first, it->second, 0); + } +} + + + + + cTeam::cTeam(const AString & a_Name, const AString & a_DisplayName, const AString & a_Prefix, const AString & a_Suffix) : m_AllowsFriendlyFire(true) @@ -397,11 +412,19 @@ void cScoreboard::SetDisplay(const AString & a_Objective, eDisplaySlot a_Slot) cObjective * Objective = GetObjective(a_Objective); - m_Display[a_Slot] = Objective; + SetDisplay(Objective, a_Slot); +} + + + + + +void cScoreboard::SetDisplay(cObjective * a_Objective, eDisplaySlot a_Slot) +{ + m_Display[a_Slot] = a_Objective; ASSERT(m_World != NULL); - m_World->BroadcastDisplayObjective(Objective ? a_Objective : "", a_Slot); - + m_World->BroadcastDisplayObjective(a_Objective ? a_Objective->GetName() : "", a_Slot); } @@ -440,6 +463,31 @@ void cScoreboard::ForEachObjectiveWith(cObjective::eType a_Type, cObjectiveCallb +void cScoreboard::SendTo(cClientHandle & a_Client) +{ + cCSLock Lock(m_CSObjectives); + + for (cObjectiveMap::iterator it = m_Objectives.begin(); it != m_Objectives.end(); ++it) + { + it->second.SendTo(a_Client); + } + + for (int i = 0; i < (int) E_DISPLAY_SLOT_COUNT; ++i) + { + // Avoid race conditions + cObjective * Objective = m_Display[i]; + + if (Objective) + { + a_Client.SendDisplayObjective(Objective->GetName(), (eDisplaySlot) i); + } + } +} + + + + + unsigned int cScoreboard::GetNumObjectives(void) const { return m_Objectives.size(); diff --git a/src/Scoreboard.h b/src/Scoreboard.h index b92642a9a..11b456739 100644 --- a/src/Scoreboard.h +++ b/src/Scoreboard.h @@ -22,10 +22,13 @@ typedef cItemCallback cObjectiveCallback; +// tolua_begin class cObjective { public: + // tolua_end + typedef int Score; enum eType @@ -82,6 +85,9 @@ public: void SetDisplayName(const AString & a_Name); + /// Send this objective to the specified client + void SendTo(cClientHandle & a_Client); + private: typedef std::pair cTrackedPlayer; @@ -105,10 +111,13 @@ private: +// tolua_begin class cTeam { public: + // tolua_end + cTeam( const AString & a_Name, const AString & a_DisplayName, const AString & a_Prefix, const AString & a_Suffix @@ -169,10 +178,13 @@ private: +// tolua_begin class cScoreboard { public: + // tolua_end + enum eDisplaySlot { E_DISPLAY_SLOT_LIST = 0, @@ -209,11 +221,16 @@ public: void SetDisplay(const AString & a_Objective, eDisplaySlot a_Slot); + void SetDisplay(cObjective * 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); + /// Send this scoreboard to the specified client + void SendTo(cClientHandle & a_Client); + unsigned int GetNumObjectives(void) const; unsigned int GetNumTeams(void) const; From dd04f5a73ccc125be80a3ba3a3ab508ac300b99a Mon Sep 17 00:00:00 2001 From: andrew Date: Wed, 22 Jan 2014 15:49:21 +0200 Subject: [PATCH 7/7] cWorld now saves/loads the scoreboard --- src/Scoreboard.cpp | 3 +++ src/Scoreboard.h | 32 ++++++++++++++++------- src/World.cpp | 9 +++++++ src/WorldStorage/ScoreboardSerializer.cpp | 15 +++++++---- 4 files changed, 44 insertions(+), 15 deletions(-) diff --git a/src/Scoreboard.cpp b/src/Scoreboard.cpp index e6812d3d7..b2edd613b 100644 --- a/src/Scoreboard.cpp +++ b/src/Scoreboard.cpp @@ -238,6 +238,8 @@ bool cTeam::HasPlayer(const AString & a_Name) const void cTeam::Reset(void) { + // TODO 2014-01-22 xdot: Inform online players + m_Players.clear(); } @@ -505,3 +507,4 @@ unsigned int cScoreboard::GetNumTeams(void) const + diff --git a/src/Scoreboard.h b/src/Scoreboard.h index 11b456739..f64ba2bce 100644 --- a/src/Scoreboard.h +++ b/src/Scoreboard.h @@ -27,8 +27,6 @@ class cObjective { public: - // tolua_end - typedef int Score; enum eType @@ -52,6 +50,8 @@ public: E_TYPE_STAT_ENTITY_KILLED_BY }; + // tolua_end + static AString TypeToString(eType a_Type); static eType StringToType(const AString & a_Name); @@ -60,6 +60,8 @@ public: cObjective(const AString & a_Name, const AString & a_DisplayName, eType a_Type, cWorld * a_World); + // tolua_begin + eType GetType(void) const { return m_Type; } const AString & GetName(void) const { return m_Name; } @@ -85,6 +87,8 @@ public: void SetDisplayName(const AString & a_Name); + // tolua_end + /// Send this objective to the specified client void SendTo(cClientHandle & a_Client); @@ -135,6 +139,8 @@ public: /// Removes all registered players void Reset(void); + // tolua_begin + /// Returns the number of registered players unsigned int GetNumPlayers(void) const; @@ -147,13 +153,15 @@ public: const AString & GetPrefix(void) const { return m_Prefix; } const AString & GetSuffix(void) const { return m_Suffix; } - void SetFriendlyFire(bool a_Flag) { m_AllowsFriendlyFire = 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); - void SetPrefix(const AString & a_Prefix); - void SetSuffix(const AString & a_Suffix); + void SetPrefix(const AString & a_Prefix) { m_Prefix = a_Prefix; } + void SetSuffix(const AString & a_Suffix) { m_Suffix = a_Suffix; } + + // tolua_end private: @@ -183,8 +191,6 @@ class cScoreboard { public: - // tolua_end - enum eDisplaySlot { E_DISPLAY_SLOT_LIST = 0, @@ -194,11 +200,15 @@ public: E_DISPLAY_SLOT_COUNT }; + // tolua_end + public: cScoreboard(cWorld * a_World); + // tolua_begin + /// Registers a new scoreboard objective, returns the cObjective instance, NULL on name collision cObjective * RegisterObjective(const AString & a_Name, const AString & a_DisplayName, cObjective::eType a_Type); @@ -228,13 +238,15 @@ public: /// Execute callback for each objective with the specified type void ForEachObjectiveWith(cObjective::eType a_Type, cObjectiveCallback& a_Callback); - /// Send this scoreboard to the specified client - void SendTo(cClientHandle & a_Client); - unsigned int GetNumObjectives(void) const; unsigned int GetNumTeams(void) const; + // tolua_end + + /// Send this scoreboard to the specified client + void SendTo(cClientHandle & a_Client); + private: diff --git a/src/World.cpp b/src/World.cpp index f83de0342..49d42f08e 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -12,6 +12,7 @@ #include "ChunkMap.h" #include "Generating/ChunkDesc.h" #include "OSSupport/Timer.h" +#include "WorldStorage/ScoreboardSerializer.h" // Entities (except mobs): #include "Entities/ExpOrb.h" @@ -248,6 +249,10 @@ cWorld::cWorld(const AString & a_WorldName) : LOGD("cWorld::cWorld(\"%s\")", a_WorldName.c_str()); cFile::CreateFolder(FILE_IO_PREFIX + m_WorldName); + + // Load the scoreboard + cScoreboardSerializer Serializer(m_WorldName, &m_Scoreboard); + Serializer.Load(); } @@ -267,6 +272,10 @@ cWorld::~cWorld() m_Storage.WaitForFinish(); + // Unload the scoreboard + cScoreboardSerializer Serializer(m_WorldName, &m_Scoreboard); + Serializer.Save(); + delete m_ChunkMap; } diff --git a/src/WorldStorage/ScoreboardSerializer.cpp b/src/WorldStorage/ScoreboardSerializer.cpp index bcac50bb6..dabc5e2e1 100644 --- a/src/WorldStorage/ScoreboardSerializer.cpp +++ b/src/WorldStorage/ScoreboardSerializer.cpp @@ -22,7 +22,12 @@ cScoreboardSerializer::cScoreboardSerializer(const AString & a_WorldName, cScoreboard* a_ScoreBoard) : m_ScoreBoard(a_ScoreBoard) { - Printf(m_Path, "%s/data/scoreboard.dat", a_WorldName.c_str()); + AString DataPath; + Printf(DataPath, "%s/data", a_WorldName.c_str()); + + m_Path = DataPath + "/scoreboard.dat"; + + cFile::CreateFolder(FILE_IO_PREFIX + DataPath); } @@ -33,7 +38,7 @@ bool cScoreboardSerializer::Load(void) { cFile File; - if (!File.Open(m_Path, cFile::fmReadWrite)) + if (!File.Open(FILE_IO_PREFIX + m_Path, cFile::fmReadWrite)) { return false; } @@ -60,7 +65,7 @@ bool cScoreboardSerializer::Load(void) { return false; } - + // Parse the NBT data: cParsedNBT NBT(Uncompressed, strm.total_out); if (!NBT.IsValid()) @@ -81,7 +86,7 @@ bool cScoreboardSerializer::Save(void) cFastNBTWriter Writer; Writer.BeginCompound(""); - + m_ScoreBoard->RegisterObjective("test","test",cObjective::E_TYPE_DUMMY)->AddScore("dot", 2); SaveScoreboardToNBT(Writer); Writer.EndCompound(); @@ -91,7 +96,7 @@ bool cScoreboardSerializer::Save(void) 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) {