commit
26586fdb92
@ -263,6 +263,12 @@ void cClientHandle::Authenticate(void)
|
|||||||
m_Player->Initialize(World);
|
m_Player->Initialize(World);
|
||||||
m_State = csAuthenticated;
|
m_State = csAuthenticated;
|
||||||
|
|
||||||
|
// Query player team
|
||||||
|
m_Player->UpdateTeam();
|
||||||
|
|
||||||
|
// Send scoreboard data
|
||||||
|
World->GetScoreBoard().SendTo(*this);
|
||||||
|
|
||||||
cRoot::Get()->GetPluginManager()->CallHookPlayerSpawned(*m_Player);
|
cRoot::Get()->GetPluginManager()->CallHookPlayerSpawned(*m_Player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2111,6 +2117,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)
|
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);
|
m_Protocol->SendSoundEffect(a_SoundName, a_SrcX, a_SrcY, a_SrcZ, a_Volume, a_Pitch);
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "OSSupport/SocketThreads.h"
|
#include "OSSupport/SocketThreads.h"
|
||||||
#include "ChunkDef.h"
|
#include "ChunkDef.h"
|
||||||
#include "ByteBuffer.h"
|
#include "ByteBuffer.h"
|
||||||
|
#include "Scoreboard.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -125,6 +126,9 @@ public:
|
|||||||
void SendRespawn (void);
|
void SendRespawn (void);
|
||||||
void SendExperience (void);
|
void SendExperience (void);
|
||||||
void SendExperienceOrb (const cExpOrb & a_ExpOrb);
|
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 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 SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data);
|
||||||
void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock);
|
void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock);
|
||||||
|
@ -74,6 +74,7 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
|
|||||||
, m_IsChargingBow(false)
|
, m_IsChargingBow(false)
|
||||||
, m_BowCharge(0)
|
, m_BowCharge(0)
|
||||||
, m_FloaterID(-1)
|
, m_FloaterID(-1)
|
||||||
|
, m_Team(NULL)
|
||||||
{
|
{
|
||||||
LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d",
|
LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d",
|
||||||
a_PlayerName.c_str(), a_Client->GetIPString().c_str(),
|
a_PlayerName.c_str(), a_Client->GetIPString().c_str(),
|
||||||
@ -791,6 +792,20 @@ void cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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->AllowsFriendlyFire())
|
||||||
|
{
|
||||||
|
// Friendly fire is disabled
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
super::DoTakeDamage(a_TDI);
|
super::DoTakeDamage(a_TDI);
|
||||||
|
|
||||||
// Any kind of damage adds food exhaustion
|
// Any kind of damage adds food exhaustion
|
||||||
@ -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()));
|
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(cObjective::E_TYPE_DEATH_COUNT, IncrementCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -916,6 +949,50 @@ bool cPlayer::IsGameModeAdventure(void) const
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cPlayer::SetTeam(cTeam * a_Team)
|
||||||
|
{
|
||||||
|
if (m_Team == a_Team)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_Team)
|
||||||
|
{
|
||||||
|
m_Team->RemovePlayer(GetName());
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Team = a_Team;
|
||||||
|
|
||||||
|
if (m_Team)
|
||||||
|
{
|
||||||
|
m_Team->AddPlayer(GetName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cTeam * cPlayer::UpdateTeam(void)
|
||||||
|
{
|
||||||
|
if (m_World == NULL)
|
||||||
|
{
|
||||||
|
SetTeam(NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cScoreboard & Scoreboard = m_World->GetScoreBoard();
|
||||||
|
|
||||||
|
SetTeam(Scoreboard.QueryPlayerTeam(GetName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_Team;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cPlayer::OpenWindow(cWindow * a_Window)
|
void cPlayer::OpenWindow(cWindow * a_Window)
|
||||||
{
|
{
|
||||||
if (a_Window != m_CurrentWindow)
|
if (a_Window != m_CurrentWindow)
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
class cGroup;
|
class cGroup;
|
||||||
class cWindow;
|
class cWindow;
|
||||||
class cClientHandle;
|
class cClientHandle;
|
||||||
|
class cTeam;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -153,6 +154,15 @@ public:
|
|||||||
|
|
||||||
AString GetIP(void) const { return m_IP; } // tolua_export
|
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);
|
||||||
|
|
||||||
|
/// Forces the player to query the scoreboard for his team
|
||||||
|
cTeam * UpdateTeam(void);
|
||||||
|
|
||||||
// tolua_end
|
// tolua_end
|
||||||
|
|
||||||
void SetIP(const AString & a_IP);
|
void SetIP(const AString & a_IP);
|
||||||
@ -456,6 +466,8 @@ protected:
|
|||||||
|
|
||||||
int m_FloaterID;
|
int m_FloaterID;
|
||||||
|
|
||||||
|
cTeam* m_Team;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void ResolvePermissions(void);
|
void ResolvePermissions(void);
|
||||||
@ -463,7 +475,7 @@ protected:
|
|||||||
|
|
||||||
virtual void Destroyed(void);
|
virtual void Destroyed(void);
|
||||||
|
|
||||||
/// Filters out damage for creative mode
|
/// Filters out damage for creative mode/friendly fire
|
||||||
virtual void DoTakeDamage(TakeDamageInfo & TDI) override;
|
virtual void DoTakeDamage(TakeDamageInfo & TDI) override;
|
||||||
|
|
||||||
/// Called in each tick to handle food-related processing
|
/// Called in each tick to handle food-related processing
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include "../Defines.h"
|
#include "../Defines.h"
|
||||||
#include "../Endianness.h"
|
#include "../Endianness.h"
|
||||||
|
#include "../Scoreboard.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -92,6 +93,9 @@ public:
|
|||||||
virtual void SendRespawn (void) = 0;
|
virtual void SendRespawn (void) = 0;
|
||||||
virtual void SendExperience (void) = 0;
|
virtual void SendExperience (void) = 0;
|
||||||
virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) = 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 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 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;
|
virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) = 0;
|
||||||
|
@ -68,6 +68,9 @@ public:
|
|||||||
virtual void SendRespawn (void) override;
|
virtual void SendRespawn (void) override;
|
||||||
virtual void SendExperience (void) override;
|
virtual void SendExperience (void) override;
|
||||||
virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) 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 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 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 SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override;
|
||||||
|
@ -37,6 +37,9 @@ enum
|
|||||||
{
|
{
|
||||||
PACKET_WINDOW_OPEN = 0x64,
|
PACKET_WINDOW_OPEN = 0x64,
|
||||||
PACKET_PARTICLE_EFFECT = 0x3F,
|
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)
|
int cProtocol150::ParseWindowClick(void)
|
||||||
{
|
{
|
||||||
HANDLE_PACKET_READ(ReadChar, char, WindowID);
|
HANDLE_PACKET_READ(ReadChar, char, WindowID);
|
||||||
|
@ -30,6 +30,9 @@ public:
|
|||||||
|
|
||||||
virtual void SendWindowOpen (const cWindow & a_Window) override;
|
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 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);
|
virtual int ParseWindowClick(void);
|
||||||
} ;
|
} ;
|
||||||
|
@ -706,6 +706,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
|
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
|
cPacketizer Pkt(*this, 0x29); // Sound Effect packet
|
||||||
|
@ -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 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 SendExperience (void) override;
|
||||||
virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) 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 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 SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override;
|
||||||
virtual void SendSpawnMob (const cMonster & a_Mob) override;
|
virtual void SendSpawnMob (const cMonster & a_Mob) override;
|
||||||
|
@ -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)
|
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);
|
ASSERT(m_Protocol != NULL);
|
||||||
|
@ -103,6 +103,9 @@ public:
|
|||||||
virtual void SendRespawn (void) override;
|
virtual void SendRespawn (void) override;
|
||||||
virtual void SendExperience (void) override;
|
virtual void SendExperience (void) override;
|
||||||
virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) 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 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 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 SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override;
|
||||||
|
510
src/Scoreboard.cpp
Normal file
510
src/Scoreboard.cpp
Normal file
@ -0,0 +1,510 @@
|
|||||||
|
|
||||||
|
// Scoreboard.cpp
|
||||||
|
|
||||||
|
// Implementation of a scoreboard that keeps track of specified objectives
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
|
||||||
|
#include "Scoreboard.h"
|
||||||
|
#include "World.h"
|
||||||
|
#include "ClientHandle.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AString cObjective::TypeToString(eType a_Type)
|
||||||
|
{
|
||||||
|
switch (a_Type)
|
||||||
|
{
|
||||||
|
case E_TYPE_DUMMY: return "dummy";
|
||||||
|
case E_TYPE_DEATH_COUNT: return "deathCount";
|
||||||
|
case E_TYPE_PLAYER_KILL_COUNT: return "playerKillCount";
|
||||||
|
case E_TYPE_TOTAL_KILL_COUNT: return "totalKillCount";
|
||||||
|
case E_TYPE_HEALTH: return "health";
|
||||||
|
case E_TYPE_ACHIEVEMENT: return "achievement";
|
||||||
|
case E_TYPE_STAT: return "stat";
|
||||||
|
case E_TYPE_STAT_ITEM_CRAFT: return "stat.craftItem";
|
||||||
|
case E_TYPE_STAT_ITEM_USE: return "stat.useItem";
|
||||||
|
case E_TYPE_STAT_ITEM_BREAK: return "stat.breakItem";
|
||||||
|
case E_TYPE_STAT_BLOCK_MINE: return "stat.mineBlock";
|
||||||
|
case E_TYPE_STAT_ENTITY_KILL: return "stat.killEntity";
|
||||||
|
case E_TYPE_STAT_ENTITY_KILLED_BY: return "stat.entityKilledBy";
|
||||||
|
|
||||||
|
default: return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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_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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cObjective::Score cObjective::GetScore(const AString & a_Name) const
|
||||||
|
{
|
||||||
|
cScoreMap::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;
|
||||||
|
|
||||||
|
m_World->BroadcastScoreUpdate(m_Name, a_Name, a_Score, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cObjective::ResetScore(const AString & a_Name)
|
||||||
|
{
|
||||||
|
m_Scores.erase(a_Name);
|
||||||
|
|
||||||
|
m_World->BroadcastScoreUpdate(m_Name, a_Name, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
SetScore(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;
|
||||||
|
|
||||||
|
SetScore(a_Name, NewScore);
|
||||||
|
|
||||||
|
return NewScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cObjective::SetDisplayName(const AString & a_Name)
|
||||||
|
{
|
||||||
|
m_DisplayName = a_Name;
|
||||||
|
|
||||||
|
m_World->BroadcastScoreboardObjective(m_Name, m_DisplayName, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
, m_CanSeeFriendlyInvisible(false)
|
||||||
|
, m_Name(a_Name)
|
||||||
|
, m_DisplayName(a_DisplayName)
|
||||||
|
, m_Prefix(a_Prefix)
|
||||||
|
, m_Suffix(a_Suffix)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cTeam::AddPlayer(const AString & a_Name)
|
||||||
|
{
|
||||||
|
return m_Players.insert(a_Name).second;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cTeam::RemovePlayer(const AString & a_Name)
|
||||||
|
{
|
||||||
|
return m_Players.erase(a_Name) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
// TODO 2014-01-22 xdot: Inform online players
|
||||||
|
|
||||||
|
m_Players.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int cTeam::GetNumPlayers(void) const
|
||||||
|
{
|
||||||
|
return m_Players.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cScoreboard::cScoreboard(cWorld * a_World) : m_World(a_World)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < (int) E_DISPLAY_SLOT_COUNT; ++i)
|
||||||
|
{
|
||||||
|
m_Display[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cObjective* cScoreboard::RegisterObjective(const AString & a_Name, const AString & a_DisplayName, cObjective::eType a_Type)
|
||||||
|
{
|
||||||
|
cObjective Objective(a_Name, a_DisplayName, a_Type, m_World);
|
||||||
|
|
||||||
|
std::pair<cObjectiveMap::iterator, bool> Status = m_Objectives.insert(cNamedObjective(a_Name, Objective));
|
||||||
|
|
||||||
|
if (Status.second)
|
||||||
|
{
|
||||||
|
ASSERT(m_World != NULL);
|
||||||
|
m_World->BroadcastScoreboardObjective(a_Name, a_DisplayName, 0);
|
||||||
|
|
||||||
|
return &Status.first->second;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cScoreboard::RemoveObjective(const AString & a_Name)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSObjectives);
|
||||||
|
|
||||||
|
cObjectiveMap::iterator it = m_Objectives.find(a_Name);
|
||||||
|
|
||||||
|
if (it == m_Objectives.end())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Objectives.erase(it);
|
||||||
|
|
||||||
|
ASSERT(m_World != NULL);
|
||||||
|
m_World->BroadcastScoreboardObjective(it->second.GetName(), it->second.GetDisplayName(), 1);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cObjective * cScoreboard::GetObjective(const AString & a_Name)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSObjectives);
|
||||||
|
|
||||||
|
cObjectiveMap::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(a_Name, a_DisplayName, a_Prefix, a_Suffix);
|
||||||
|
|
||||||
|
std::pair<cTeamMap::iterator, bool> Status = m_Teams.insert(cNamedTeam(a_Name, Team));
|
||||||
|
|
||||||
|
return Status.second ? &Status.first->second : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cScoreboard::RemoveTeam(const AString & a_Name)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSTeams);
|
||||||
|
|
||||||
|
cTeamMap::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)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSTeams);
|
||||||
|
|
||||||
|
cTeamMap::iterator it = m_Teams.find(a_Name);
|
||||||
|
|
||||||
|
if (it == m_Teams.end())
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return &it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
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(a_Objective ? a_Objective->GetName() : "", a_Slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSObjectives);
|
||||||
|
|
||||||
|
for (cObjectiveMap::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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int cScoreboard::GetNumTeams(void) const
|
||||||
|
{
|
||||||
|
return m_Teams.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
276
src/Scoreboard.h
Normal file
276
src/Scoreboard.h
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
|
||||||
|
// Scoreboard.h
|
||||||
|
|
||||||
|
// Implementation of a scoreboard that keeps track of specified objectives
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cObjective;
|
||||||
|
class cWorld;
|
||||||
|
|
||||||
|
typedef cItemCallback<cObjective> cObjectiveCallback;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// tolua_begin
|
||||||
|
class cObjective
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef int Score;
|
||||||
|
|
||||||
|
enum eType
|
||||||
|
{
|
||||||
|
E_TYPE_DUMMY,
|
||||||
|
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
// tolua_end
|
||||||
|
|
||||||
|
static AString TypeToString(eType a_Type);
|
||||||
|
|
||||||
|
static eType StringToType(const AString & a_Name);
|
||||||
|
|
||||||
|
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; }
|
||||||
|
const AString & GetDisplayName(void) const { return m_DisplayName; }
|
||||||
|
|
||||||
|
/// 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);
|
||||||
|
|
||||||
|
void SetDisplayName(const AString & a_Name);
|
||||||
|
|
||||||
|
// tolua_end
|
||||||
|
|
||||||
|
/// Send this objective to the specified client
|
||||||
|
void SendTo(cClientHandle & a_Client);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
typedef std::pair<AString, Score> cTrackedPlayer;
|
||||||
|
|
||||||
|
typedef std::map<AString, Score> cScoreMap;
|
||||||
|
|
||||||
|
cScoreMap m_Scores;
|
||||||
|
|
||||||
|
AString m_DisplayName;
|
||||||
|
AString m_Name;
|
||||||
|
|
||||||
|
eType m_Type;
|
||||||
|
|
||||||
|
cWorld * m_World;
|
||||||
|
|
||||||
|
friend class cScoreboardSerializer;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// tolua_begin
|
||||||
|
class cTeam
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
// tolua_end
|
||||||
|
|
||||||
|
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(const AString & a_Name);
|
||||||
|
|
||||||
|
/// 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);
|
||||||
|
|
||||||
|
// tolua_begin
|
||||||
|
|
||||||
|
/// Returns the number of registered players
|
||||||
|
unsigned int GetNumPlayers(void) const;
|
||||||
|
|
||||||
|
bool AllowsFriendlyFire(void) const { return m_AllowsFriendlyFire; }
|
||||||
|
bool CanSeeFriendlyInvisible(void) const { return m_CanSeeFriendlyInvisible; }
|
||||||
|
|
||||||
|
const AString & GetDisplayName(void) const { return m_DisplayName; }
|
||||||
|
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) { 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) { m_Prefix = a_Prefix; }
|
||||||
|
void SetSuffix(const AString & a_Suffix) { m_Suffix = a_Suffix; }
|
||||||
|
|
||||||
|
// tolua_end
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
typedef std::set<AString> cPlayerNameSet;
|
||||||
|
|
||||||
|
bool m_AllowsFriendlyFire;
|
||||||
|
bool m_CanSeeFriendlyInvisible;
|
||||||
|
|
||||||
|
AString m_DisplayName;
|
||||||
|
AString m_Name;
|
||||||
|
|
||||||
|
AString m_Prefix;
|
||||||
|
AString m_Suffix;
|
||||||
|
|
||||||
|
cPlayerNameSet m_Players;
|
||||||
|
|
||||||
|
friend class cScoreboardSerializer;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// tolua_begin
|
||||||
|
class cScoreboard
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum eDisplaySlot
|
||||||
|
{
|
||||||
|
E_DISPLAY_SLOT_LIST = 0,
|
||||||
|
E_DISPLAY_SLOT_SIDEBAR,
|
||||||
|
E_DISPLAY_SLOT_NAME,
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
/// 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, NULL on name collision
|
||||||
|
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 * QueryPlayerTeam(const AString & a_Name); // WARNING: O(n logn)
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
typedef std::pair<AString, cObjective> cNamedObjective;
|
||||||
|
typedef std::pair<AString, cTeam> cNamedTeam;
|
||||||
|
|
||||||
|
typedef std::map<AString, cObjective> cObjectiveMap;
|
||||||
|
typedef std::map<AString, cTeam> cTeamMap;
|
||||||
|
|
||||||
|
// TODO 2014-01-19 xdot: Potential optimization - Sort objectives based on type
|
||||||
|
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;
|
||||||
|
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
|||||||
#include "ChunkMap.h"
|
#include "ChunkMap.h"
|
||||||
#include "Generating/ChunkDesc.h"
|
#include "Generating/ChunkDesc.h"
|
||||||
#include "OSSupport/Timer.h"
|
#include "OSSupport/Timer.h"
|
||||||
|
#include "WorldStorage/ScoreboardSerializer.h"
|
||||||
|
|
||||||
// Entities (except mobs):
|
// Entities (except mobs):
|
||||||
#include "Entities/ExpOrb.h"
|
#include "Entities/ExpOrb.h"
|
||||||
@ -242,11 +243,16 @@ cWorld::cWorld(const AString & a_WorldName) :
|
|||||||
m_Weather(eWeather_Sunny),
|
m_Weather(eWeather_Sunny),
|
||||||
m_WeatherInterval(24000), // Guaranteed 1 day of sunshine at server start :)
|
m_WeatherInterval(24000), // Guaranteed 1 day of sunshine at server start :)
|
||||||
m_GeneratorCallbacks(*this),
|
m_GeneratorCallbacks(*this),
|
||||||
m_TickThread(*this)
|
m_TickThread(*this),
|
||||||
|
m_Scoreboard(this)
|
||||||
{
|
{
|
||||||
LOGD("cWorld::cWorld(\"%s\")", a_WorldName.c_str());
|
LOGD("cWorld::cWorld(\"%s\")", a_WorldName.c_str());
|
||||||
|
|
||||||
cFile::CreateFolder(FILE_IO_PREFIX + m_WorldName);
|
cFile::CreateFolder(FILE_IO_PREFIX + m_WorldName);
|
||||||
|
|
||||||
|
// Load the scoreboard
|
||||||
|
cScoreboardSerializer Serializer(m_WorldName, &m_Scoreboard);
|
||||||
|
Serializer.Load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -266,6 +272,10 @@ cWorld::~cWorld()
|
|||||||
|
|
||||||
m_Storage.WaitForFinish();
|
m_Storage.WaitForFinish();
|
||||||
|
|
||||||
|
// Unload the scoreboard
|
||||||
|
cScoreboardSerializer Serializer(m_WorldName, &m_Scoreboard);
|
||||||
|
Serializer.Save();
|
||||||
|
|
||||||
delete m_ChunkMap;
|
delete m_ChunkMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1981,6 +1991,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)
|
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);
|
m_ChunkMap->BroadcastSoundEffect(a_SoundName, a_SrcX, a_SrcY, a_SrcZ, a_Volume, a_Pitch, a_Exclude);
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "Item.h"
|
#include "Item.h"
|
||||||
#include "Mobs/Monster.h"
|
#include "Mobs/Monster.h"
|
||||||
#include "Entities/ProjectileEntity.h"
|
#include "Entities/ProjectileEntity.h"
|
||||||
|
#include "Scoreboard.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -169,6 +170,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 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 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 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 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 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);
|
void BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
|
||||||
@ -505,6 +509,9 @@ public:
|
|||||||
/** Returns the name of the world.ini file used by this world */
|
/** Returns the name of the world.ini file used by this world */
|
||||||
const AString & GetIniFileName(void) const {return m_IniFileName; }
|
const AString & GetIniFileName(void) const {return m_IniFileName; }
|
||||||
|
|
||||||
|
/// Returns the associated scoreboard instance
|
||||||
|
cScoreboard & GetScoreBoard(void) { return m_Scoreboard; }
|
||||||
|
|
||||||
// tolua_end
|
// tolua_end
|
||||||
|
|
||||||
inline static void AbsoluteToRelative( int & a_X, int & a_Y, int & a_Z, int & a_ChunkX, int & a_ChunkY, int & a_ChunkZ )
|
inline static void AbsoluteToRelative( int & a_X, int & a_Y, int & a_Z, int & a_ChunkX, int & a_ChunkY, int & a_ChunkZ )
|
||||||
@ -773,6 +780,8 @@ private:
|
|||||||
|
|
||||||
cChunkGenerator m_Generator;
|
cChunkGenerator m_Generator;
|
||||||
|
|
||||||
|
cScoreboard m_Scoreboard;
|
||||||
|
|
||||||
/** The callbacks that the ChunkGenerator uses to store new chunks and interface to plugins */
|
/** The callbacks that the ChunkGenerator uses to store new chunks and interface to plugins */
|
||||||
cChunkGeneratorCallbacks m_GeneratorCallbacks;
|
cChunkGeneratorCallbacks m_GeneratorCallbacks;
|
||||||
|
|
||||||
|
389
src/WorldStorage/ScoreboardSerializer.cpp
Normal file
389
src/WorldStorage/ScoreboardSerializer.cpp
Normal file
@ -0,0 +1,389 @@
|
|||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
AString DataPath;
|
||||||
|
Printf(DataPath, "%s/data", a_WorldName.c_str());
|
||||||
|
|
||||||
|
m_Path = DataPath + "/scoreboard.dat";
|
||||||
|
|
||||||
|
cFile::CreateFolder(FILE_IO_PREFIX + DataPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cScoreboardSerializer::Load(void)
|
||||||
|
{
|
||||||
|
cFile File;
|
||||||
|
|
||||||
|
if (!File.Open(FILE_IO_PREFIX + 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("");
|
||||||
|
m_ScoreBoard->RegisterObjective("test","test",cObjective::E_TYPE_DUMMY)->AddScore("dot", 2);
|
||||||
|
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);
|
||||||
|
|
||||||
|
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.EndCompound();
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
52
src/WorldStorage/ScoreboardSerializer.h
Normal file
52
src/WorldStorage/ScoreboardSerializer.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1936,7 +1936,7 @@ bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_N
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
a_Entity.SetYaw(Rotation[0]);
|
a_Entity.SetYaw(Rotation[0]);
|
||||||
a_Entity.SetRoll (Rotation[1]);
|
a_Entity.SetRoll(Rotation[1]);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user