1
0
Fork 0
cuberite-2a/src/Scoreboard.cpp

606 lines
9.7 KiB
C++
Raw Normal View History

2014-01-19 12:20:57 +00:00
// Scoreboard.cpp
// Implementation of a scoreboard that keeps track of specified objectives
#include "Globals.h"
#include "Scoreboard.h"
2014-01-21 13:58:17 +00:00
#include "World.h"
2014-01-21 17:43:13 +00:00
#include "ClientHandle.h"
2014-01-19 12:20:57 +00:00
2014-01-20 14:10:39 +00:00
AString cObjective::TypeToString(eType a_Type)
{
switch (a_Type)
{
2014-03-01 12:20:29 +00:00
case otDummy: return "dummy";
case otDeathCount: return "deathCount";
case otPlayerKillCount: return "playerKillCount";
case otTotalKillCount: return "totalKillCount";
case otHealth: return "health";
case otAchievement: return "achievement";
case otStat: return "stat";
case otStatItemCraft: return "stat.craftItem";
case otStatItemUse: return "stat.useItem";
case otStatItemBreak: return "stat.breakItem";
case otStatBlockMine: return "stat.mineBlock";
case otStatEntityKill: return "stat.killEntity";
case otStatEntityKilledBy: return "stat.entityKilledBy";
2014-01-20 14:10:39 +00:00
}
UNREACHABLE("Unsupported objective type");
2014-01-20 14:10:39 +00:00
}
2014-01-19 12:20:57 +00:00
2014-01-20 14:10:39 +00:00
cObjective::eType cObjective::StringToType(const AString & a_Name)
2014-01-19 12:20:57 +00:00
{
static struct
{
2014-01-20 14:10:39 +00:00
eType m_Type;
const char * m_String;
} TypeMap [] =
{
2014-03-01 12:20:29 +00:00
{otDummy, "dummy" },
{otDeathCount, "deathCount" },
{otPlayerKillCount, "playerKillCount" },
{otTotalKillCount, "totalKillCount" },
{otHealth, "health" },
{otAchievement, "achievement" },
{otStat, "stat" },
{otStatItemCraft, "stat.craftItem" },
{otStatItemUse, "stat.useItem" },
{otStatItemBreak, "stat.breakItem" },
{otStatBlockMine, "stat.mineBlock" },
{otStatEntityKill, "stat.killEntity" },
{otStatEntityKilledBy, "stat.entityKilledBy"}
2014-01-20 14:10:39 +00:00
};
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[]
2014-03-01 12:20:29 +00:00
return otDummy;
2014-01-19 12:20:57 +00:00
}
2014-01-21 13:58:17 +00:00
cObjective::cObjective(const AString & a_Name, const AString & a_DisplayName, cObjective::eType a_Type, cWorld * a_World)
2014-01-20 14:45:40 +00:00
: m_DisplayName(a_DisplayName)
, m_Name(a_Name)
, m_Type(a_Type)
2014-01-21 13:58:17 +00:00
, m_World(a_World)
{
}
2014-01-20 14:10:39 +00:00
2014-01-19 12:20:57 +00:00
void cObjective::Reset(void)
{
2014-01-21 13:58:17 +00:00
for (cScoreMap::iterator it = m_Scores.begin(); it != m_Scores.end(); ++it)
{
m_World->BroadcastScoreUpdate(m_Name, it->first, 0, 1);
}
2014-01-19 12:20:57 +00:00
m_Scores.clear();
}
cObjective::Score cObjective::GetScore(const AString & a_Name) const
{
2014-01-20 14:45:40 +00:00
cScoreMap::const_iterator it = m_Scores.find(a_Name);
2014-01-19 12:20:57 +00:00
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;
2014-01-21 13:58:17 +00:00
m_World->BroadcastScoreUpdate(m_Name, a_Name, a_Score, 0);
2014-01-19 12:20:57 +00:00
}
void cObjective::ResetScore(const AString & a_Name)
{
m_Scores.erase(a_Name);
2014-01-21 13:58:17 +00:00
m_World->BroadcastScoreUpdate(m_Name, a_Name, 0, 1);
2014-01-19 12:20:57 +00:00
}
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;
2014-01-21 13:58:17 +00:00
SetScore(a_Name, NewScore);
2014-01-19 12:20:57 +00:00
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;
2014-01-21 13:58:17 +00:00
SetScore(a_Name, NewScore);
2014-01-19 12:20:57 +00:00
return NewScore;
}
2014-01-21 13:58:17 +00:00
void cObjective::SetDisplayName(const AString & a_Name)
{
m_DisplayName = a_Name;
m_World->BroadcastScoreboardObjective(m_Name, m_DisplayName, 2);
}
2014-01-21 17:43:13 +00:00
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
)
2014-01-19 14:02:37 +00:00
: m_AllowsFriendlyFire(true)
, m_CanSeeFriendlyInvisible(false)
2014-01-19 12:20:57 +00:00
, m_DisplayName(a_DisplayName)
2014-02-05 17:43:49 +00:00
, m_Name(a_Name)
2014-01-19 12:20:57 +00:00
, m_Prefix(a_Prefix)
, m_Suffix(a_Suffix)
{
}
2014-01-19 12:20:57 +00:00
2014-01-19 14:02:37 +00:00
bool cTeam::AddPlayer(const AString & a_Name)
2014-01-19 12:20:57 +00:00
{
2014-01-19 14:02:37 +00:00
return m_Players.insert(a_Name).second;
2014-01-19 12:20:57 +00:00
}
2014-01-19 14:02:37 +00:00
bool cTeam::RemovePlayer(const AString & a_Name)
2014-01-19 12:20:57 +00:00
{
2014-01-19 14:02:37 +00:00
return m_Players.erase(a_Name) > 0;
2014-01-19 12:20:57 +00:00
}
2014-01-20 14:10:39 +00:00
bool cTeam::HasPlayer(const AString & a_Name) const
{
cPlayerNameSet::const_iterator it = m_Players.find(a_Name);
return it != m_Players.end();
}
2014-01-19 12:20:57 +00:00
void cTeam::Reset(void)
{
2014-01-22 13:49:21 +00:00
// TODO 2014-01-22 xdot: Inform online players
2014-01-19 12:20:57 +00:00
m_Players.clear();
}
2014-03-01 10:06:19 +00:00
void cTeam::SetDisplayName(const AString & a_Name)
{
m_DisplayName = a_Name;
// TODO 2014-03-01 xdot: Update clients
}
2014-05-08 18:16:35 +00:00
size_t cTeam::GetNumPlayers(void) const
2014-01-19 12:20:57 +00:00
{
return m_Players.size();
}
2014-01-21 13:58:17 +00:00
cScoreboard::cScoreboard(cWorld * a_World) : m_World(a_World)
2014-01-19 12:20:57 +00:00
{
2015-05-24 11:56:56 +00:00
for (int i = 0; i < static_cast<int>(dsCount); ++i)
2014-01-20 14:10:39 +00:00
{
2014-10-20 20:55:07 +00:00
m_Display[i] = nullptr;
2014-01-20 14:10:39 +00:00
}
}
2014-01-19 12:20:57 +00:00
2014-01-20 14:10:39 +00:00
cObjective * cScoreboard::RegisterObjective(const AString & a_Name, const AString & a_DisplayName, cObjective::eType a_Type)
2014-01-20 14:10:39 +00:00
{
2014-01-21 13:58:17 +00:00
cObjective Objective(a_Name, a_DisplayName, a_Type, m_World);
2014-01-20 14:10:39 +00:00
std::pair<cObjectiveMap::iterator, bool> Status = m_Objectives.insert(cNamedObjective(a_Name, Objective));
2014-01-19 12:20:57 +00:00
2014-01-21 13:58:17 +00:00
if (Status.second)
{
2014-10-20 20:55:07 +00:00
ASSERT(m_World != nullptr);
2014-01-21 13:58:17 +00:00
m_World->BroadcastScoreboardObjective(a_Name, a_DisplayName, 0);
return &Status.first->second;
}
else
{
2014-10-20 20:55:07 +00:00
return nullptr;
2014-01-21 13:58:17 +00:00
}
2014-01-19 12:20:57 +00:00
}
bool cScoreboard::RemoveObjective(const AString & a_Name)
{
2014-01-21 13:58:17 +00:00
cCSLock Lock(m_CSObjectives);
2014-01-20 14:10:39 +00:00
cObjectiveMap::iterator it = m_Objectives.find(a_Name);
2014-01-19 12:20:57 +00:00
if (it == m_Objectives.end())
{
return false;
}
2014-10-20 20:55:07 +00:00
ASSERT(m_World != nullptr);
2014-01-21 13:58:17 +00:00
m_World->BroadcastScoreboardObjective(it->second.GetName(), it->second.GetDisplayName(), 1);
2015-05-24 11:56:56 +00:00
for (unsigned int i = 0; i < static_cast<unsigned int>(dsCount); ++i)
{
if (m_Display[i] == &it->second)
{
2015-05-24 11:56:56 +00:00
SetDisplay(nullptr, static_cast<eDisplaySlot>(i));
}
}
m_Objectives.erase(it);
2014-03-01 10:06:19 +00:00
2014-01-19 12:20:57 +00:00
return true;
}
2014-01-20 14:10:39 +00:00
cObjective * cScoreboard::GetObjective(const AString & a_Name)
2014-01-19 12:20:57 +00:00
{
2014-01-21 13:58:17 +00:00
cCSLock Lock(m_CSObjectives);
2014-01-20 14:10:39 +00:00
cObjectiveMap::iterator it = m_Objectives.find(a_Name);
2014-01-19 12:20:57 +00:00
if (it == m_Objectives.end())
{
2014-10-20 20:55:07 +00:00
return nullptr;
2014-01-19 12:20:57 +00:00
}
else
{
2014-01-19 14:02:37 +00:00
return &it->second;
2014-01-19 12:20:57 +00:00
}
}
2014-01-20 14:10:39 +00:00
cTeam * cScoreboard::RegisterTeam(
2014-01-19 14:02:37 +00:00
const AString & a_Name, const AString & a_DisplayName,
const AString & a_Prefix, const AString & a_Suffix
)
2014-01-19 12:20:57 +00:00
{
2014-01-19 14:02:37 +00:00
cTeam Team(a_Name, a_DisplayName, a_Prefix, a_Suffix);
2014-01-19 12:20:57 +00:00
2014-01-20 14:10:39 +00:00
std::pair<cTeamMap::iterator, bool> Status = m_Teams.insert(cNamedTeam(a_Name, Team));
2014-01-19 12:20:57 +00:00
2014-10-20 20:55:07 +00:00
return Status.second ? &Status.first->second : nullptr;
2014-01-19 12:20:57 +00:00
}
bool cScoreboard::RemoveTeam(const AString & a_Name)
{
2014-01-21 13:58:17 +00:00
cCSLock Lock(m_CSTeams);
2014-01-20 14:10:39 +00:00
cTeamMap::iterator it = m_Teams.find(a_Name);
2014-01-19 12:20:57 +00:00
if (it == m_Teams.end())
{
return false;
}
m_Teams.erase(it);
return true;
}
2014-01-20 14:10:39 +00:00
cTeam * cScoreboard::GetTeam(const AString & a_Name)
2014-01-19 12:20:57 +00:00
{
2014-01-21 13:58:17 +00:00
cCSLock Lock(m_CSTeams);
2014-01-20 14:10:39 +00:00
cTeamMap::iterator it = m_Teams.find(a_Name);
2014-01-19 12:20:57 +00:00
if (it == m_Teams.end())
{
2014-10-20 20:55:07 +00:00
return nullptr;
2014-01-19 12:20:57 +00:00
}
else
{
2014-01-19 14:02:37 +00:00
return &it->second;
2014-01-19 12:20:57 +00:00
}
}
AStringVector cScoreboard::GetTeamNames()
{
AStringVector TeamNames;
for (const auto & Team: m_Teams)
{
TeamNames.push_back(Team.first);
}
return TeamNames;
}
2014-01-20 14:10:39 +00:00
cTeam * cScoreboard::QueryPlayerTeam(const AString & a_Name)
{
2014-01-21 13:58:17 +00:00
cCSLock Lock(m_CSTeams);
2014-01-20 14:10:39 +00:00
for (cTeamMap::iterator it = m_Teams.begin(); it != m_Teams.end(); ++it)
{
if (it->second.HasPlayer(a_Name))
{
return &it->second;
}
}
2014-10-20 20:55:07 +00:00
return nullptr;
2014-01-20 14:10:39 +00:00
}
void cScoreboard::SetDisplay(const AString & a_Objective, eDisplaySlot a_Slot)
{
2014-03-01 12:20:29 +00:00
ASSERT(a_Slot < dsCount);
2014-01-20 14:10:39 +00:00
cObjective * Objective = GetObjective(a_Objective);
2014-01-21 17:43:13 +00:00
SetDisplay(Objective, a_Slot);
}
void cScoreboard::SetDisplay(cObjective * a_Objective, eDisplaySlot a_Slot)
{
m_Display[a_Slot] = a_Objective;
2014-01-21 13:58:17 +00:00
2014-10-20 20:55:07 +00:00
ASSERT(m_World != nullptr);
2014-01-21 17:43:13 +00:00
m_World->BroadcastDisplayObjective(a_Objective ? a_Objective->GetName() : "", a_Slot);
2014-01-20 14:10:39 +00:00
}
2014-01-20 14:45:40 +00:00
cObjective * cScoreboard::GetObjectiveIn(eDisplaySlot a_Slot)
2014-01-20 14:10:39 +00:00
{
2014-03-01 12:20:29 +00:00
ASSERT(a_Slot < dsCount);
2014-01-20 14:10:39 +00:00
return m_Display[a_Slot];
}
bool cScoreboard::ForEachObjectiveWith(cObjective::eType a_Type, cObjectiveCallback a_Callback)
2014-01-19 12:20:57 +00:00
{
2014-01-21 13:58:17 +00:00
cCSLock Lock(m_CSObjectives);
2014-01-20 14:10:39 +00:00
for (cObjectiveMap::iterator it = m_Objectives.begin(); it != m_Objectives.end(); ++it)
2014-01-19 12:20:57 +00:00
{
2014-01-19 14:02:37 +00:00
if (it->second.GetType() == a_Type)
2014-01-19 12:20:57 +00:00
{
// Call callback
if (a_Callback(it->second))
2014-01-19 12:20:57 +00:00
{
2014-03-01 12:03:16 +00:00
return false;
2014-01-19 12:20:57 +00:00
}
}
}
2014-03-01 12:03:16 +00:00
return true;
}
bool cScoreboard::ForEachObjective(cObjectiveCallback a_Callback)
2014-03-01 12:03:16 +00:00
{
cCSLock Lock(m_CSObjectives);
for (cObjectiveMap::iterator it = m_Objectives.begin(); it != m_Objectives.end(); ++it)
{
// Call callback
if (a_Callback(it->second))
2014-03-01 12:27:55 +00:00
{
return false;
}
}
return true;
}
bool cScoreboard::ForEachTeam(cTeamCallback a_Callback)
2014-03-01 12:27:55 +00:00
{
cCSLock Lock(m_CSTeams);
2014-03-01 12:27:55 +00:00
for (cTeamMap::iterator it = m_Teams.begin(); it != m_Teams.end(); ++it)
{
// Call callback
if (a_Callback(it->second))
2014-03-01 12:03:16 +00:00
{
return false;
}
}
return true;
2014-01-19 12:20:57 +00:00
}
2014-01-20 14:10:39 +00:00
2014-03-01 10:06:19 +00:00
void cScoreboard::AddPlayerScore(const AString & a_Name, cObjective::eType a_Type, cObjective::Score a_Value)
{
cCSLock Lock(m_CSObjectives);
for (cObjectiveMap::iterator it = m_Objectives.begin(); it != m_Objectives.end(); ++it)
{
if (it->second.GetType() == a_Type)
{
it->second.AddScore(a_Name, a_Value);
}
}
}
2014-01-21 17:43:13 +00:00
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);
}
2015-05-24 11:56:56 +00:00
for (int i = 0; i < static_cast<int>(dsCount); ++i)
2014-01-21 17:43:13 +00:00
{
// Avoid race conditions
cObjective * Objective = m_Display[i];
if (Objective)
{
2015-05-24 11:56:56 +00:00
a_Client.SendDisplayObjective(Objective->GetName(), static_cast<eDisplaySlot>(i));
2014-01-21 17:43:13 +00:00
}
}
}
2014-05-08 18:16:35 +00:00
size_t cScoreboard::GetNumObjectives(void) const
2014-01-20 14:10:39 +00:00
{
return m_Objectives.size();
}
2014-05-08 18:16:35 +00:00
size_t cScoreboard::GetNumTeams(void) const
2014-01-20 14:10:39 +00:00
{
return m_Teams.size();
}
2014-01-22 13:49:21 +00:00