Cuberite
A lightweight, fast and extensible game server for Minecraft
Scoreboard.cpp
Go to the documentation of this file.
1 
2 // Scoreboard.cpp
3 
4 // Implementation of a scoreboard that keeps track of specified objectives
5 
6 #include "Globals.h"
7 
8 #include "Scoreboard.h"
9 #include "World.h"
10 #include "ClientHandle.h"
11 
12 
13 
14 
15 
17 {
18  switch (a_Type)
19  {
20  case otDummy: return "dummy";
21  case otDeathCount: return "deathCount";
22  case otPlayerKillCount: return "playerKillCount";
23  case otTotalKillCount: return "totalKillCount";
24  case otHealth: return "health";
25  case otAchievement: return "achievement";
26  case otStat: return "stat";
27  case otStatItemCraft: return "stat.craftItem";
28  case otStatItemUse: return "stat.useItem";
29  case otStatItemBreak: return "stat.breakItem";
30  case otStatBlockMine: return "stat.mineBlock";
31  case otStatEntityKill: return "stat.killEntity";
32  case otStatEntityKilledBy: return "stat.entityKilledBy";
33  }
34  UNREACHABLE("Unsupported objective type");
35 }
36 
37 
38 
39 
40 
42 {
43  static struct
44  {
45  eType m_Type;
46  const char * m_String;
47  } TypeMap [] =
48  {
49  {otDummy, "dummy" },
50  {otDeathCount, "deathCount" },
51  {otPlayerKillCount, "playerKillCount" },
52  {otTotalKillCount, "totalKillCount" },
53  {otHealth, "health" },
54  {otAchievement, "achievement" },
55  {otStat, "stat" },
56  {otStatItemCraft, "stat.craftItem" },
57  {otStatItemUse, "stat.useItem" },
58  {otStatItemBreak, "stat.breakItem" },
59  {otStatBlockMine, "stat.mineBlock" },
60  {otStatEntityKill, "stat.killEntity" },
61  {otStatEntityKilledBy, "stat.entityKilledBy"}
62  };
63  for (size_t i = 0; i < ARRAYCOUNT(TypeMap); i++)
64  {
65  if (NoCaseCompare(TypeMap[i].m_String, a_Name) == 0)
66  {
67  return TypeMap[i].m_Type;
68  }
69  } // for i - TypeMap[]
70  return otDummy;
71 }
72 
73 
74 
75 
76 
77 cObjective::cObjective(const AString & a_Name, const AString & a_DisplayName, cObjective::eType a_Type, cWorld * a_World)
78  : m_DisplayName(a_DisplayName)
79  , m_Name(a_Name)
80  , m_Type(a_Type)
81  , m_World(a_World)
82 {
83 }
84 
85 
86 
87 
88 
90 {
91  for (cScoreMap::iterator it = m_Scores.begin(); it != m_Scores.end(); ++it)
92  {
93  m_World->BroadcastScoreUpdate(m_Name, it->first, 0, 1);
94  }
95 
96  m_Scores.clear();
97 }
98 
99 
100 
101 
102 
104 {
105  cScoreMap::const_iterator it = m_Scores.find(a_Name);
106 
107  if (it == m_Scores.end())
108  {
109  return 0;
110  }
111  else
112  {
113  return it->second;
114  }
115 }
116 
117 
118 
119 
120 
121 void cObjective::SetScore(const AString & a_Name, cObjective::Score a_Score)
122 {
123  m_Scores[a_Name] = a_Score;
124 
125  m_World->BroadcastScoreUpdate(m_Name, a_Name, a_Score, 0);
126 }
127 
128 
129 
130 
131 
132 void cObjective::ResetScore(const AString & a_Name)
133 {
134  m_Scores.erase(a_Name);
135 
136  m_World->BroadcastScoreUpdate(m_Name, a_Name, 0, 1);
137 }
138 
139 
140 
141 
142 
144 {
145  // TODO 2014-01-19 xdot: Potential optimization - Reuse iterator
146  Score NewScore = m_Scores[a_Name] + a_Delta;
147 
148  SetScore(a_Name, NewScore);
149 
150  return NewScore;
151 }
152 
153 
154 
155 
156 
158 {
159  // TODO 2014-01-19 xdot: Potential optimization - Reuse iterator
160  Score NewScore = m_Scores[a_Name] - a_Delta;
161 
162  SetScore(a_Name, NewScore);
163 
164  return NewScore;
165 }
166 
167 
168 
169 
170 
172 {
173  m_DisplayName = a_Name;
174 
176 }
177 
178 
179 
180 
181 
183 {
185 
186  for (cScoreMap::const_iterator it = m_Scores.begin(); it != m_Scores.end(); ++it)
187  {
188  a_Client.SendScoreUpdate(m_Name, it->first, it->second, 0);
189  }
190 }
191 
192 
193 
194 
195 
197  const AString & a_Name, const AString & a_DisplayName,
198  const AString & a_Prefix, const AString & a_Suffix
199 )
200  : m_AllowsFriendlyFire(true)
201  , m_CanSeeFriendlyInvisible(false)
202  , m_DisplayName(a_DisplayName)
203  , m_Name(a_Name)
204  , m_Prefix(a_Prefix)
205  , m_Suffix(a_Suffix)
206 {
207 }
208 
209 
210 
211 
212 
213 bool cTeam::AddPlayer(const AString & a_Name)
214 {
215  return m_Players.insert(a_Name).second;
216 }
217 
218 
219 
220 
221 
222 bool cTeam::RemovePlayer(const AString & a_Name)
223 {
224  return m_Players.erase(a_Name) > 0;
225 }
226 
227 
228 
229 
230 
231 bool cTeam::HasPlayer(const AString & a_Name) const
232 {
233  cPlayerNameSet::const_iterator it = m_Players.find(a_Name);
234 
235  return it != m_Players.end();
236 }
237 
238 
239 
240 
241 
242 void cTeam::Reset(void)
243 {
244  // TODO 2014-01-22 xdot: Inform online players
245 
246  m_Players.clear();
247 }
248 
249 
250 
251 
252 
253 void cTeam::SetDisplayName(const AString & a_Name)
254 {
255  m_DisplayName = a_Name;
256 
257  // TODO 2014-03-01 xdot: Update clients
258 }
259 
260 
261 
262 
263 
264 size_t cTeam::GetNumPlayers(void) const
265 {
266  return m_Players.size();
267 }
268 
269 
270 
271 
272 
273 cScoreboard::cScoreboard(cWorld * a_World) : m_World(a_World)
274 {
275  for (int i = 0; i < static_cast<int>(dsCount); ++i)
276  {
277  m_Display[i] = nullptr;
278  }
279 }
280 
281 
282 
283 
284 
285 cObjective * cScoreboard::RegisterObjective(const AString & a_Name, const AString & a_DisplayName, cObjective::eType a_Type)
286 {
287  cObjective Objective(a_Name, a_DisplayName, a_Type, m_World);
288 
289  std::pair<cObjectiveMap::iterator, bool> Status = m_Objectives.insert(cNamedObjective(a_Name, Objective));
290 
291  if (Status.second)
292  {
293  ASSERT(m_World != nullptr);
294  m_World->BroadcastScoreboardObjective(a_Name, a_DisplayName, 0);
295 
296  return &Status.first->second;
297  }
298  else
299  {
300  return nullptr;
301  }
302 }
303 
304 
305 
306 
307 
309 {
310  cCSLock Lock(m_CSObjectives);
311 
312  cObjectiveMap::iterator it = m_Objectives.find(a_Name);
313 
314  if (it == m_Objectives.end())
315  {
316  return false;
317  }
318 
319  ASSERT(m_World != nullptr);
320  m_World->BroadcastScoreboardObjective(it->second.GetName(), it->second.GetDisplayName(), 1);
321 
322  for (unsigned int i = 0; i < static_cast<unsigned int>(dsCount); ++i)
323  {
324  if (m_Display[i] == &it->second)
325  {
326  SetDisplay(nullptr, static_cast<eDisplaySlot>(i));
327  }
328  }
329 
330  m_Objectives.erase(it);
331 
332  return true;
333 }
334 
335 
336 
337 
338 
340 {
341  cCSLock Lock(m_CSObjectives);
342 
343  cObjectiveMap::iterator it = m_Objectives.find(a_Name);
344 
345  if (it == m_Objectives.end())
346  {
347  return nullptr;
348  }
349  else
350  {
351  return &it->second;
352  }
353 }
354 
355 
356 
357 
358 
360  const AString & a_Name, const AString & a_DisplayName,
361  const AString & a_Prefix, const AString & a_Suffix
362 )
363 {
364  auto [TeamIterator, TeamExists] = m_Teams.try_emplace(a_Name, a_Name, a_DisplayName, a_Prefix, a_Suffix);
365 
366  if (!TeamExists && GetTeam(a_Name))
367  {
368  LOGWARNING("Tried to register a team that already exists: %s", a_Name.c_str());
369  return nullptr;
370  }
371 
372  return &TeamIterator->second;
373 }
374 
375 
376 
377 
378 
379 bool cScoreboard::RemoveTeam(const AString & a_Name)
380 {
381  cCSLock Lock(m_CSTeams);
382 
383  cTeamMap::iterator it = m_Teams.find(a_Name);
384 
385  if (it == m_Teams.end())
386  {
387  return false;
388  }
389 
390  m_Teams.erase(it);
391 
392  return true;
393 }
394 
395 
396 
397 
398 
400 {
401  cCSLock Lock(m_CSTeams);
402 
403  cTeamMap::iterator it = m_Teams.find(a_Name);
404 
405  if (it == m_Teams.end())
406  {
407  return nullptr;
408  }
409  else
410  {
411  return &it->second;
412  }
413 }
414 
415 
416 
417 
418 
420 {
421  AStringVector TeamNames;
422 
423  for (const auto & Team: m_Teams)
424  {
425  TeamNames.push_back(Team.first);
426  }
427 
428  return TeamNames;
429 }
430 
431 
432 
433 
434 
436 {
437  cCSLock Lock(m_CSTeams);
438 
439  for (cTeamMap::iterator it = m_Teams.begin(); it != m_Teams.end(); ++it)
440  {
441  if (it->second.HasPlayer(a_Name))
442  {
443  return &it->second;
444  }
445  }
446 
447  return nullptr;
448 }
449 
450 
451 
452 
453 
454 void cScoreboard::SetDisplay(const AString & a_Objective, eDisplaySlot a_Slot)
455 {
456  ASSERT(a_Slot < dsCount);
457 
458  cObjective * Objective = GetObjective(a_Objective);
459 
460  SetDisplay(Objective, a_Slot);
461 }
462 
463 
464 
465 
466 
468 {
469  m_Display[a_Slot] = a_Objective;
470 
471  ASSERT(m_World != nullptr);
472  m_World->BroadcastDisplayObjective(a_Objective ? a_Objective->GetName() : "", a_Slot);
473 }
474 
475 
476 
477 
478 
480 {
481  ASSERT(a_Slot < dsCount);
482 
483  return m_Display[a_Slot];
484 }
485 
486 
487 
488 
489 
491 {
492  cCSLock Lock(m_CSObjectives);
493 
494  for (cObjectiveMap::iterator it = m_Objectives.begin(); it != m_Objectives.end(); ++it)
495  {
496  if (it->second.GetType() == a_Type)
497  {
498  // Call callback
499  if (a_Callback(it->second))
500  {
501  return false;
502  }
503  }
504  }
505  return true;
506 }
507 
508 
509 
510 
511 
513 {
514  cCSLock Lock(m_CSObjectives);
515 
516  for (cObjectiveMap::iterator it = m_Objectives.begin(); it != m_Objectives.end(); ++it)
517  {
518  // Call callback
519  if (a_Callback(it->second))
520  {
521  return false;
522  }
523  }
524  return true;
525 }
526 
527 
528 
529 
530 
532 {
533  cCSLock Lock(m_CSTeams);
534 
535  for (cTeamMap::iterator it = m_Teams.begin(); it != m_Teams.end(); ++it)
536  {
537  // Call callback
538  if (a_Callback(it->second))
539  {
540  return false;
541  }
542  }
543  return true;
544 }
545 
546 
547 
548 
549 
551 {
552  cCSLock Lock(m_CSObjectives);
553 
554  for (cObjectiveMap::iterator it = m_Objectives.begin(); it != m_Objectives.end(); ++it)
555  {
556  if (it->second.GetType() == a_Type)
557  {
558  it->second.AddScore(a_Name, a_Value);
559  }
560  }
561 }
562 
563 
564 
565 
566 
568 {
569  cCSLock Lock(m_CSObjectives);
570 
571  for (cObjectiveMap::iterator it = m_Objectives.begin(); it != m_Objectives.end(); ++it)
572  {
573  it->second.SendTo(a_Client);
574  }
575 
576  for (int i = 0; i < static_cast<int>(dsCount); ++i)
577  {
578  // Avoid race conditions
579  cObjective * Objective = m_Display[i];
580 
581  if (Objective)
582  {
583  a_Client.SendDisplayObjective(Objective->GetName(), static_cast<eDisplaySlot>(i));
584  }
585  }
586 }
587 
588 
589 
590 
591 
593 {
594  return m_Objectives.size();
595 }
596 
597 
598 
599 
600 
601 size_t cScoreboard::GetNumTeams(void) const
602 {
603  return m_Teams.size();
604 }
605 
606 
607 
608 
609 
const char * m_String
Definition: BiomeDef.cpp:17
#define UNREACHABLE(x)
Definition: Globals.h:288
#define ARRAYCOUNT(X)
Evaluates to the number of elements in an array (compile-time!)
Definition: Globals.h:231
#define ASSERT(x)
Definition: Globals.h:276
void LOGWARNING(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:67
eMonsterType m_Type
Definition: Monster.cpp:35
int NoCaseCompare(const AString &s1, const AString &s2)
Case-insensitive string comparison.
std::vector< AString > AStringVector
Definition: StringUtils.h:12
std::string AString
Definition: StringUtils.h:11
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)
RAII for cCriticalSection - locks the CS on creation, unlocks on destruction.
cScoreMap m_Scores
Definition: Scoreboard.h:106
Score AddScore(const AString &a_Name, Score a_Delta)
Adds a_Delta and returns the new score.
Definition: Scoreboard.cpp:143
@ otStatItemCraft
Definition: Scoreboard.h:49
@ otStatEntityKill
Definition: Scoreboard.h:54
@ otTotalKillCount
Definition: Scoreboard.h:43
@ otAchievement
Definition: Scoreboard.h:46
@ otStatBlockMine
Definition: Scoreboard.h:53
@ otStatItemBreak
Definition: Scoreboard.h:51
@ otStatEntityKilledBy
Definition: Scoreboard.h:55
@ otStatItemUse
Definition: Scoreboard.h:50
@ otDeathCount
Definition: Scoreboard.h:41
@ otPlayerKillCount
Definition: Scoreboard.h:42
void SetDisplayName(const AString &a_Name)
Definition: Scoreboard.cpp:171
static eType StringToType(const AString &a_Name)
Definition: Scoreboard.cpp:41
eType m_Type
Definition: Scoreboard.h:111
void Reset(void)
Resets the objective.
Definition: Scoreboard.cpp:89
cObjective(const AString &a_Name, const AString &a_DisplayName, eType a_Type, cWorld *a_World)
Definition: Scoreboard.cpp:77
void SetScore(const AString &a_Name, Score a_Score)
Sets the score of the specified player.
Definition: Scoreboard.cpp:121
cWorld * m_World
Definition: Scoreboard.h:113
const AString & GetName(void) const
Definition: Scoreboard.h:72
AString m_DisplayName
Definition: Scoreboard.h:108
static AString TypeToString(eType a_Type)
Definition: Scoreboard.cpp:16
Score SubScore(const AString &a_Name, Score a_Delta)
Subtracts a_Delta and returns the new score.
Definition: Scoreboard.cpp:157
void ResetScore(const AString &a_Name)
Resets the score of the specified player.
Definition: Scoreboard.cpp:132
Score GetScore(const AString &a_Name) const
Returns the score of the specified player.
Definition: Scoreboard.cpp:103
AString m_Name
Definition: Scoreboard.h:109
void SendTo(cClientHandle &a_Client)
Send this objective to the specified client.
Definition: Scoreboard.cpp:182
cPlayerNameSet m_Players
Definition: Scoreboard.h:187
size_t GetNumPlayers(void) const
Returns the number of registered players.
Definition: Scoreboard.cpp:264
cTeam(const AString &a_Name, const AString &a_DisplayName, const AString &a_Prefix, const AString &a_Suffix)
Definition: Scoreboard.cpp:196
void SetDisplayName(const AString &a_Name)
Definition: Scoreboard.cpp:253
AString m_DisplayName
Definition: Scoreboard.h:181
void Reset(void)
Removes all registered players.
Definition: Scoreboard.cpp:242
bool HasPlayer(const AString &a_Name) const
Returns whether the specified player is in this team.
Definition: Scoreboard.cpp:231
bool RemovePlayer(const AString &a_Name)
Removes a player from the team.
Definition: Scoreboard.cpp:222
bool AddPlayer(const AString &a_Name)
Adds a new player to the team.
Definition: Scoreboard.cpp:213
size_t GetNumObjectives(void) const
Definition: Scoreboard.cpp:592
cObjective * GetObjective(const AString &a_Name)
Retrieves the objective with the specified name, nullptr if not found.
Definition: Scoreboard.cpp:339
AStringVector GetTeamNames()
Retrieves the list of team names.
Definition: Scoreboard.cpp:419
cTeam * RegisterTeam(const AString &a_Name, const AString &a_DisplayName, const AString &a_Prefix, const AString &a_Suffix)
Registers a new team, returns the cTeam instance, nullptr on name collision.
Definition: Scoreboard.cpp:359
cTeam * QueryPlayerTeam(const AString &a_Name)
Definition: Scoreboard.cpp:435
size_t GetNumTeams(void) const
Definition: Scoreboard.cpp:601
cObjectiveMap m_Objectives
Definition: Scoreboard.h:284
cObjective * GetObjectiveIn(eDisplaySlot a_Slot)
Definition: Scoreboard.cpp:479
bool ForEachObjectiveWith(cObjective::eType a_Type, cObjectiveCallback a_Callback)
Execute callback for each objective with the specified type Returns true if all objectives processed,...
Definition: Scoreboard.cpp:490
cTeam * GetTeam(const AString &a_Name)
Retrieves the team with the specified name, nullptr if not found.
Definition: Scoreboard.cpp:399
bool ForEachTeam(cTeamCallback a_Callback)
Execute callback for each team.
Definition: Scoreboard.cpp:531
void AddPlayerScore(const AString &a_Name, cObjective::eType a_Type, cObjective::Score a_Value=1)
Definition: Scoreboard.cpp:550
void SendTo(cClientHandle &a_Client)
Send this scoreboard to the specified client.
Definition: Scoreboard.cpp:567
cCriticalSection m_CSObjectives
Definition: Scoreboard.h:283
cObjective * m_Display[dsCount]
Definition: Scoreboard.h:291
cScoreboard(cWorld *a_World)
Definition: Scoreboard.cpp:273
cObjective * RegisterObjective(const AString &a_Name, const AString &a_DisplayName, cObjective::eType a_Type)
Registers a new scoreboard objective, returns the cObjective instance, nullptr on name collision.
Definition: Scoreboard.cpp:285
void SetDisplay(const AString &a_Objective, eDisplaySlot a_Slot)
Definition: Scoreboard.cpp:454
bool ForEachObjective(cObjectiveCallback a_Callback)
Execute callback for each objective.
Definition: Scoreboard.cpp:512
std::pair< AString, cObjective > cNamedObjective
Definition: Scoreboard.h:276
bool RemoveObjective(const AString &a_Name)
Removes a registered objective, returns true if operation was successful.
Definition: Scoreboard.cpp:308
cTeamMap m_Teams
Definition: Scoreboard.h:287
cWorld * m_World
Definition: Scoreboard.h:289
bool RemoveTeam(const AString &a_Name)
Removes a registered team, returns true if operation was successful.
Definition: Scoreboard.cpp:379
cCriticalSection m_CSTeams
Definition: Scoreboard.h:286
Definition: World.h:53
virtual void BroadcastScoreboardObjective(const AString &a_Name, const AString &a_DisplayName, Byte a_Mode) override
virtual void BroadcastScoreUpdate(const AString &a_Objective, const AString &a_Player, cObjective::Score a_Score, Byte a_Mode) override
virtual void BroadcastDisplayObjective(const AString &a_Objective, cScoreboard::eDisplaySlot a_Display) override