From 7d0813ce8c1be14bc1b9b706644bd4aa797244ee Mon Sep 17 00:00:00 2001 From: 12xx12 <44411062+12xx12@users.noreply.github.com> Date: Wed, 12 Aug 2020 09:54:36 +0100 Subject: Add Statistics and Achievements for newer Network standards --- src/Entities/Entity.cpp | 6 +-- src/Entities/Pickup.cpp | 8 ++-- src/Entities/Player.cpp | 113 ++++++++++++++++++++++++------------------------ src/Entities/Player.h | 5 +-- 4 files changed, 66 insertions(+), 66 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index ae468d25c..b8d17aaa3 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -544,7 +544,7 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) } } - Player->GetStatManager().AddValue(statDamageDealt, static_cast(floor(a_TDI.FinalDamage * 10 + 0.5))); + Player->GetStatManager().AddValue(Statistic::DamageDealt, FloorC(a_TDI.FinalDamage * 10 + 0.5)); } m_Health -= a_TDI.FinalDamage; @@ -1426,7 +1426,7 @@ bool cEntity::DetectPortal() { if (DestionationDim == dimNether) { - static_cast(this)->AwardAchievement(achEnterPortal); + static_cast(this)->AwardAchievement(Statistic::AchPortal); } static_cast(this)->GetClientHandle()->SendRespawn(DestionationDim); @@ -1505,7 +1505,7 @@ bool cEntity::DetectPortal() { if (DestionationDim == dimEnd) { - static_cast(this)->AwardAchievement(achEnterTheEnd); + static_cast(this)->AwardAchievement(Statistic::AchTheEnd); } static_cast(this)->GetClientHandle()->SendRespawn(DestionationDim); } diff --git a/src/Entities/Pickup.cpp b/src/Entities/Pickup.cpp index 1faeadaa7..4b05c2b9b 100644 --- a/src/Entities/Pickup.cpp +++ b/src/Entities/Pickup.cpp @@ -242,10 +242,10 @@ bool cPickup::CollectedBy(cPlayer & a_Dest) // Check achievements switch (m_Item.m_ItemType) { - case E_BLOCK_LOG: a_Dest.AwardAchievement(achMineWood); break; - case E_ITEM_LEATHER: a_Dest.AwardAchievement(achKillCow); break; - case E_ITEM_DIAMOND: a_Dest.AwardAchievement(achDiamonds); break; - case E_ITEM_BLAZE_ROD: a_Dest.AwardAchievement(achBlazeRod); break; + case E_BLOCK_LOG: a_Dest.AwardAchievement(Statistic::AchMineWood); break; + case E_ITEM_LEATHER: a_Dest.AwardAchievement(Statistic::AchKillCow); break; + case E_ITEM_DIAMOND: a_Dest.AwardAchievement(Statistic::AchDiamonds); break; + case E_ITEM_BLAZE_ROD: a_Dest.AwardAchievement(Statistic::AchBlazeRod); break; default: break; } diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 3bfcb4039..764bd7500 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -334,7 +334,7 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) } - m_Stats.AddValue(statMinutesPlayed, 1); + m_Stats.AddValue(Statistic::PlayOneMinute, 1); // Handle the player detach, when the player is in spectator mode if ( @@ -742,7 +742,7 @@ void cPlayer::TossItems(const cItems & a_Items) return; } - m_Stats.AddValue(statItemsDropped, static_cast(a_Items.Size())); + m_Stats.AddValue(Statistic::Drop, static_cast(a_Items.Size())); const auto Speed = (GetLookVector() + Vector3d(0, 0.2, 0)) * 6; // A dash of height and a dollop of speed const auto Position = GetEyePosition() - Vector3d(0, 0.2, 0); // Correct for eye-height weirdness @@ -1110,7 +1110,7 @@ bool cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI) NotifyNearbyWolves(static_cast(a_TDI.Attacker), true); } } - m_Stats.AddValue(statDamageTaken, FloorC(a_TDI.FinalDamage * 10 + 0.5)); + m_Stats.AddValue(Statistic::DamageTaken, FloorC(a_TDI.FinalDamage * 10 + 0.5)); return true; } return false; @@ -1168,7 +1168,7 @@ void cPlayer::KilledBy(TakeDamageInfo & a_TDI) { Pickups.Add(cItem(E_ITEM_RED_APPLE)); } - m_Stats.AddValue(statItemsDropped, static_cast(Pickups.Size())); + m_Stats.AddValue(Statistic::Drop, static_cast(Pickups.Size())); m_World->SpawnItemPickups(Pickups, GetPosX(), GetPosY(), GetPosZ(), 10); SaveToDisk(); // Save it, yeah the world is a tough place ! @@ -1234,7 +1234,7 @@ void cPlayer::KilledBy(TakeDamageInfo & a_TDI) } } - m_Stats.AddValue(statDeaths); + m_Stats.AddValue(Statistic::Deaths); m_World->GetScoreBoard().AddPlayerScore(GetName(), cObjective::otDeathCount, 1); } @@ -1249,7 +1249,7 @@ void cPlayer::Killed(cEntity * a_Victim) if (a_Victim->IsPlayer()) { - m_Stats.AddValue(statPlayerKills); + m_Stats.AddValue(Statistic::PlayerKills); ScoreBoard.AddPlayerScore(GetName(), cObjective::otPlayerKillCount, 1); } @@ -1257,10 +1257,10 @@ void cPlayer::Killed(cEntity * a_Victim) { if (static_cast(a_Victim)->GetMobFamily() == cMonster::mfHostile) { - AwardAchievement(achKillMonster); + AwardAchievement(Statistic::AchKillEnemy); } - m_Stats.AddValue(statMobKills); + m_Stats.AddValue(Statistic::MobKills); } ScoreBoard.AddPlayerScore(GetName(), cObjective::otTotalKillCount, 1); @@ -1671,43 +1671,32 @@ void cPlayer::SetIP(const AString & a_IP) -unsigned int cPlayer::AwardAchievement(const eStatistic a_Ach) +void cPlayer::AwardAchievement(const Statistic a_Ach) { - eStatistic Prerequisite = cStatInfo::GetPrerequisite(a_Ach); - - // Check if the prerequisites are met - if (Prerequisite != statInvalid) + // Check if the prerequisites are met: + if (!m_Stats.SatisfiesPrerequisite(a_Ach)) { - if (m_Stats.GetValue(Prerequisite) == 0) - { - return 0; - } + return; } - StatValue Old = m_Stats.GetValue(a_Ach); - - if (Old > 0) + // Increment the statistic and check if we already have it: + if (m_Stats.AddValue(a_Ach) != 1) { - return static_cast(m_Stats.AddValue(a_Ach)); + return; } - else - { - if (m_World->ShouldBroadcastAchievementMessages()) - { - cCompositeChat Msg; - Msg.SetMessageType(mtSuccess); - Msg.AddShowAchievementPart(GetName(), cStatInfo::GetName(a_Ach)); - m_World->BroadcastChat(Msg); - } - // Increment the statistic - StatValue New = m_Stats.AddValue(a_Ach); - - // Achievement Get! - m_ClientHandle->SendStatistics(m_Stats); - - return static_cast(New); + if (m_World->ShouldBroadcastAchievementMessages()) + { + cCompositeChat Msg; + Msg.SetMessageType(mtSuccess); + // TODO: cCompositeChat should not use protocol-specific strings + // Msg.AddShowAchievementPart(GetName(), nameNew); + Msg.AddTextPart("Achivement get!"); + m_World->BroadcastChat(Msg); } + + // Achievement Get! + m_ClientHandle->SendStatistics(m_Stats); } @@ -2334,10 +2323,17 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World) m_SpawnWorld = cRoot::Get()->GetDefaultWorld(); } - // Load the player stats. - // We use the default world name (like bukkit) because stats are shared between dimensions / worlds. - cStatSerializer StatSerializer(cRoot::Get()->GetDefaultWorld()->GetDataPath(), GetName(), GetUUID().ToLongString(), &m_Stats); - StatSerializer.Load(); + try + { + // Load the player stats. + // We use the default world name (like bukkit) because stats are shared between dimensions / worlds. + cStatSerializer StatSerializer(m_Stats, cRoot::Get()->GetDefaultWorld()->GetDataPath(), GetUUID().ToLongString()); + StatSerializer.Load(); + } + catch (...) + { + LOGWARNING("Failed loading player statistics"); + } FLOGD("Player {0} was read from file \"{1}\", spawning at {2:.2f} in world \"{3}\"", GetName(), a_FileName, GetPosition(), a_World->GetName() @@ -2476,10 +2472,14 @@ bool cPlayer::SaveToDisk() return false; } - // Save the player stats. - // We use the default world name (like bukkit) because stats are shared between dimensions / worlds. - cStatSerializer StatSerializer(cRoot::Get()->GetDefaultWorld()->GetDataPath(), GetName(), GetUUID().ToLongString(), &m_Stats); - if (!StatSerializer.Save()) + try + { + // Save the player stats. + // We use the default world name (like bukkit) because stats are shared between dimensions / worlds. + cStatSerializer StatSerializer(m_Stats, cRoot::Get()->GetDefaultWorld()->GetDataPath(), GetUUID().ToLongString()); + StatSerializer.Save(); + } + catch (...) { LOGWARNING("Could not save stats for player %s", GetName().c_str()); return false; @@ -2659,12 +2659,12 @@ void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos, bool a_PreviousIs return; } - StatValue Value = FloorC(a_DeltaPos.Length() * 100 + 0.5); + const auto Value = FloorC(a_DeltaPos.Length() * 100 + 0.5); if (m_AttachedTo == nullptr) { if (IsFlying()) { - m_Stats.AddValue(statDistFlown, Value); + m_Stats.AddValue(Statistic::FlyOneCm, Value); // May be flying and doing any of the following: } @@ -2672,17 +2672,18 @@ void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos, bool a_PreviousIs { if (a_DeltaPos.y > 0.0) // Going up { - m_Stats.AddValue(statDistClimbed, FloorC(a_DeltaPos.y * 100 + 0.5)); + m_Stats.AddValue(Statistic::ClimbOneCm, FloorC(a_DeltaPos.y * 100 + 0.5)); } } else if (IsInWater()) { - m_Stats.AddValue(statDistSwum, Value); + // TODO: implement differentiation between diving and swimming + m_Stats.AddValue(Statistic::WalkUnderWaterOneCm, Value); AddFoodExhaustion(0.00015 * static_cast(Value)); } else if (IsOnGround()) { - m_Stats.AddValue(statDistWalked, Value); + m_Stats.AddValue(Statistic::WalkOneCm, Value); AddFoodExhaustion((IsSprinting() ? 0.001 : 0.0001) * static_cast(Value)); } else @@ -2690,13 +2691,13 @@ void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos, bool a_PreviousIs // If a jump just started, process food exhaustion: if ((a_DeltaPos.y > 0.0) && a_PreviousIsOnGround) { - m_Stats.AddValue(statJumps, 1); + m_Stats.AddValue(Statistic::Jump, 1); AddFoodExhaustion((IsSprinting() ? 0.008 : 0.002) * static_cast(Value)); } else if (a_DeltaPos.y < 0.0) { // Increment statistic - m_Stats.AddValue(statDistFallen, static_cast(std::abs(a_DeltaPos.y) * 100 + 0.5)); + m_Stats.AddValue(Statistic::FallOneCm, static_cast(std::abs(a_DeltaPos.y) * 100 + 0.5)); } // TODO: good opportunity to detect illegal flight (check for falling tho) } @@ -2705,15 +2706,15 @@ void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos, bool a_PreviousIs { switch (m_AttachedTo->GetEntityType()) { - case cEntity::etMinecart: m_Stats.AddValue(statDistMinecart, Value); break; - case cEntity::etBoat: m_Stats.AddValue(statDistBoat, Value); break; + case cEntity::etMinecart: m_Stats.AddValue(Statistic::MinecartOneCm, Value); break; + case cEntity::etBoat: m_Stats.AddValue(Statistic::BoatOneCm, Value); break; case cEntity::etMonster: { cMonster * Monster = static_cast(m_AttachedTo); switch (Monster->GetMobType()) { - case mtPig: m_Stats.AddValue(statDistPig, Value); break; - case mtHorse: m_Stats.AddValue(statDistHorse, Value); break; + case mtPig: m_Stats.AddValue(Statistic::PigOneCm, Value); break; + case mtHorse: m_Stats.AddValue(Statistic::HorseOneCm, Value); break; default: break; } break; diff --git a/src/Entities/Player.h b/src/Entities/Player.h index c52d6bbdc..6297ddcbc 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -235,9 +235,8 @@ public: /** Awards the player an achievement. If all prerequisites are met, this method will award the achievement and will broadcast a chat message. - If the achievement has been already awarded to the player, this method will just increment the stat counter. - Returns the _new_ stat value. (0 = Could not award achievement) */ - unsigned int AwardAchievement(const eStatistic a_Ach); + If the achievement has been already awarded to the player, this method will just increment the stat counter. */ + void AwardAchievement(Statistic a_Ach); void SetIP(const AString & a_IP); -- cgit v1.2.3