From c2f8ceb554982a33bcd4a1e168f6c4e26d0b85dd Mon Sep 17 00:00:00 2001 From: 12xx12 <44411062+12xx12@users.noreply.github.com> Date: Sat, 5 Sep 2020 17:13:44 +0200 Subject: Add more statistic tracking (#4837) + Added possible 1.8 stats + Added stat tracking for 1.8.2 + Added stat tracking for 1.9 + Added the breed cow achievement Co-authored-by: 12xx12 <12xx12100@gmail.com> --- src/BlockEntities/BeaconEntity.cpp | 2 ++ src/BlockEntities/BrewingstandEntity.cpp | 2 ++ src/BlockEntities/ChestEntity.cpp | 9 ++++++++ src/BlockEntities/DropSpenserEntity.cpp | 9 ++++++++ src/BlockEntities/EnderChestEntity.cpp | 3 +++ src/BlockEntities/FlowerPotEntity.cpp | 2 ++ src/BlockEntities/FurnaceEntity.cpp | 2 ++ src/BlockEntities/HopperEntity.cpp | 2 ++ src/BlockEntities/JukeboxEntity.cpp | 2 ++ src/BlockEntities/NoteEntity.cpp | 3 ++- src/Blocks/BlockBed.cpp | 1 + src/Blocks/BlockCake.h | 1 + src/Blocks/BlockCauldron.h | 2 ++ src/Blocks/BlockWorkbench.h | 2 ++ src/ClientHandle.cpp | 1 + src/Entities/Player.cpp | 35 +++++++++++++++++++++++++++----- src/Mobs/PassiveMonster.cpp | 12 +++++++++++ src/Mobs/PassiveMonster.h | 4 ++++ 18 files changed, 88 insertions(+), 6 deletions(-) diff --git a/src/BlockEntities/BeaconEntity.cpp b/src/BlockEntities/BeaconEntity.cpp index 9923be749..f9ceb6f34 100644 --- a/src/BlockEntities/BeaconEntity.cpp +++ b/src/BlockEntities/BeaconEntity.cpp @@ -303,6 +303,8 @@ bool cBeaconEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) bool cBeaconEntity::UsedBy(cPlayer * a_Player) { + a_Player->GetStatManager().AddValue(Statistic::InteractWithBeacon); + cWindow * Window = GetWindow(); if (Window == nullptr) { diff --git a/src/BlockEntities/BrewingstandEntity.cpp b/src/BlockEntities/BrewingstandEntity.cpp index 3f437d4cb..27dabf177 100644 --- a/src/BlockEntities/BrewingstandEntity.cpp +++ b/src/BlockEntities/BrewingstandEntity.cpp @@ -156,6 +156,8 @@ bool cBrewingstandEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) bool cBrewingstandEntity::UsedBy(cPlayer * a_Player) { + a_Player->GetStatManager().AddValue(Statistic::InteractWithBrewingstand); + cWindow * Window = GetWindow(); if (Window == nullptr) { diff --git a/src/BlockEntities/ChestEntity.cpp b/src/BlockEntities/ChestEntity.cpp index 0f005fb53..8c8e75b25 100644 --- a/src/BlockEntities/ChestEntity.cpp +++ b/src/BlockEntities/ChestEntity.cpp @@ -105,6 +105,15 @@ bool cChestEntity::UsedBy(cPlayer * a_Player) } } + if (m_BlockType == E_BLOCK_CHEST) + { + a_Player->GetStatManager().AddValue(Statistic::OpenChest); + } + else // E_BLOCK_TRAPPED_CHEST + { + a_Player->GetStatManager().AddValue(Statistic::TriggerTrappedChest); + } + // If the window is not created, open it anew: cWindow * Window = PrimaryChest->GetWindow(); if (Window == nullptr) diff --git a/src/BlockEntities/DropSpenserEntity.cpp b/src/BlockEntities/DropSpenserEntity.cpp index 2b048bce2..97a67ff60 100644 --- a/src/BlockEntities/DropSpenserEntity.cpp +++ b/src/BlockEntities/DropSpenserEntity.cpp @@ -153,6 +153,15 @@ void cDropSpenserEntity::SendTo(cClientHandle & a_Client) bool cDropSpenserEntity::UsedBy(cPlayer * a_Player) { + if (m_BlockType == E_BLOCK_DISPENSER) + { + a_Player->GetStatManager().AddValue(Statistic::InspectDispenser); + } + else // E_BLOCK_DROPPER + { + a_Player->GetStatManager().AddValue(Statistic::InspectDropper); + } + cWindow * Window = GetWindow(); if (Window == nullptr) { diff --git a/src/BlockEntities/EnderChestEntity.cpp b/src/BlockEntities/EnderChestEntity.cpp index 74e6a7d23..44bfaf7d4 100644 --- a/src/BlockEntities/EnderChestEntity.cpp +++ b/src/BlockEntities/EnderChestEntity.cpp @@ -61,6 +61,9 @@ bool cEnderChestEntity::UsedBy(cPlayer * a_Player) // Obstruction, don't open return false; } + + a_Player->GetStatManager().AddValue(Statistic::OpenEnderchest); + // If the window is not created, open it anew: cWindow * Window = GetWindow(); if (Window == nullptr) diff --git a/src/BlockEntities/FlowerPotEntity.cpp b/src/BlockEntities/FlowerPotEntity.cpp index 5446ee5bd..60b2db4f5 100644 --- a/src/BlockEntities/FlowerPotEntity.cpp +++ b/src/BlockEntities/FlowerPotEntity.cpp @@ -59,6 +59,8 @@ bool cFlowerPotEntity::UsedBy(cPlayer * a_Player) return false; } + a_Player->GetStatManager().AddValue(Statistic::PotFlower); + cItem SelectedItem = a_Player->GetInventory().GetEquippedItem(); if (IsFlower(SelectedItem.m_ItemType, SelectedItem.m_ItemDamage)) { diff --git a/src/BlockEntities/FurnaceEntity.cpp b/src/BlockEntities/FurnaceEntity.cpp index f521bf666..e8e981065 100644 --- a/src/BlockEntities/FurnaceEntity.cpp +++ b/src/BlockEntities/FurnaceEntity.cpp @@ -139,6 +139,8 @@ bool cFurnaceEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) bool cFurnaceEntity::UsedBy(cPlayer * a_Player) { + a_Player->GetStatManager().AddValue(Statistic::InteractWithFurnace); + cWindow * Window = GetWindow(); if (Window == nullptr) { diff --git a/src/BlockEntities/HopperEntity.cpp b/src/BlockEntities/HopperEntity.cpp index f7cb13b7d..9665b9f25 100644 --- a/src/BlockEntities/HopperEntity.cpp +++ b/src/BlockEntities/HopperEntity.cpp @@ -106,6 +106,8 @@ void cHopperEntity::SendTo(cClientHandle & a_Client) bool cHopperEntity::UsedBy(cPlayer * a_Player) { + a_Player->GetStatManager().AddValue(Statistic::InspectHopper); + // If the window is not created, open it anew: cWindow * Window = GetWindow(); if (Window == nullptr) diff --git a/src/BlockEntities/JukeboxEntity.cpp b/src/BlockEntities/JukeboxEntity.cpp index c8d08f327..6f25c4a36 100644 --- a/src/BlockEntities/JukeboxEntity.cpp +++ b/src/BlockEntities/JukeboxEntity.cpp @@ -70,6 +70,8 @@ bool cJukeboxEntity::UsedBy(cPlayer * a_Player) const cItem & HeldItem = a_Player->GetEquippedItem(); if (PlayRecord(HeldItem.m_ItemType) && !a_Player->IsGameModeCreative()) { + a_Player->GetStatManager().AddValue(Statistic::PlayRecord); + a_Player->GetInventory().RemoveOneEquippedItem(); return true; } diff --git a/src/BlockEntities/NoteEntity.cpp b/src/BlockEntities/NoteEntity.cpp index d56f45548..3e9958892 100644 --- a/src/BlockEntities/NoteEntity.cpp +++ b/src/BlockEntities/NoteEntity.cpp @@ -4,6 +4,7 @@ #include "NoteEntity.h" #include "../World.h" #include "json/value.h" +#include "../Entities/Player.h" @@ -33,7 +34,7 @@ void cNoteEntity::CopyFrom(const cBlockEntity & a_Src) bool cNoteEntity::UsedBy(cPlayer * a_Player) { - UNUSED(a_Player); + a_Player->GetStatManager().AddValue(Statistic::TuneNoteblock); IncrementNote(); MakeSound(); return true; diff --git a/src/Blocks/BlockBed.cpp b/src/Blocks/BlockBed.cpp index e333c0700..79e4a0019 100644 --- a/src/Blocks/BlockBed.cpp +++ b/src/Blocks/BlockBed.cpp @@ -128,6 +128,7 @@ bool cBlockBedHandler::OnUse( SetBedPos(a_Player, a_BlockPos); SetBedOccupationState(a_ChunkInterface, a_Player.GetLastBedPos(), true); a_Player.SetIsInBed(true); + a_Player.GetStatManager().AddValue(Statistic::SleepInBed); // Fast-forward the time if all players in the world are in their beds: auto TimeFastForwardTester = [](cPlayer & a_OtherPlayer) diff --git a/src/Blocks/BlockCake.h b/src/Blocks/BlockCake.h index dbcce5f17..b7506f2e7 100644 --- a/src/Blocks/BlockCake.h +++ b/src/Blocks/BlockCake.h @@ -36,6 +36,7 @@ public: return false; } + a_Player.GetStatManager().AddValue(Statistic::EatCakeSlice); if (Meta >= 5) { a_ChunkInterface.DigBlock(a_WorldInterface, a_BlockPos); diff --git a/src/Blocks/BlockCauldron.h b/src/Blocks/BlockCauldron.h index da7c43860..263f539a7 100644 --- a/src/Blocks/BlockCauldron.h +++ b/src/Blocks/BlockCauldron.h @@ -54,6 +54,7 @@ public: if (!a_Player.IsGameModeCreative()) { a_Player.ReplaceOneEquippedItemTossRest(cItem(E_ITEM_WATER_BUCKET)); + a_Player.GetStatManager().AddValue(Statistic::UseCauldron); } } break; @@ -68,6 +69,7 @@ public: { a_Player.ReplaceOneEquippedItemTossRest(cItem(E_ITEM_BUCKET)); } + a_Player.GetStatManager().AddValue(Statistic::FillCauldron); } break; } diff --git a/src/Blocks/BlockWorkbench.h b/src/Blocks/BlockWorkbench.h index 19bf551dd..329a1ddeb 100644 --- a/src/Blocks/BlockWorkbench.h +++ b/src/Blocks/BlockWorkbench.h @@ -34,6 +34,8 @@ public: const Vector3i a_CursorPos ) override { + a_Player.GetStatManager().AddValue(Statistic::InteractWithCraftingTable); + cWindow * Window = new cCraftingWindow(); a_Player.OpenWindow(*Window); return true; diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 040c3a306..86e90aa8b 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -2109,6 +2109,7 @@ void cClientHandle::Tick(float a_Dt) LOGD("Client %s @ %s (%p) has been queued for destruction, destroying now.", m_Username.c_str(), m_IPString.c_str(), static_cast(this) ); + GetPlayer()->GetStatManager().AddValue(Statistic::LeaveGame); Destroy(); return; } diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 841b70b01..d9353f67f 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -334,7 +334,12 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) } - m_Stats.AddValue(Statistic::PlayOneMinute, 1); + m_Stats.AddValue(Statistic::PlayOneMinute); + m_Stats.AddValue(Statistic::TimeSinceDeath); + if (IsCrouched()) + { + m_Stats.AddValue(Statistic::SneakTime); + } // Handle the player detach, when the player is in spectator mode if ( @@ -1235,6 +1240,7 @@ void cPlayer::KilledBy(TakeDamageInfo & a_TDI) } m_Stats.AddValue(Statistic::Deaths); + m_Stats.SetValue(Statistic::TimeSinceDeath, 0); m_World->GetScoreBoard().AddPlayerScore(GetName(), cObjective::otDeathCount, 1); } @@ -2675,14 +2681,33 @@ void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos, bool a_PreviousIs } else if (IsInWater()) { - // TODO: implement differentiation between diving and swimming - m_Stats.AddValue(Statistic::WalkUnderWaterOneCm, Value); + if (m_IsHeadInWater) + { + m_Stats.AddValue(Statistic::WalkUnderWaterOneCm, Value); + } + else + { + m_Stats.AddValue(Statistic::WalkOnWaterOneCm, Value); + } AddFoodExhaustion(0.00015 * static_cast(Value)); } else if (IsOnGround()) { - m_Stats.AddValue(Statistic::WalkOneCm, Value); - AddFoodExhaustion((IsSprinting() ? 0.001 : 0.0001) * static_cast(Value)); + if (IsCrouched()) + { + m_Stats.AddValue(Statistic::CrouchOneCm, Value); + AddFoodExhaustion(0.0001 * static_cast(Value)); + } + if (IsSprinting()) + { + m_Stats.AddValue(Statistic::SprintOneCm, Value); + AddFoodExhaustion(0.001 * static_cast(Value)); + } + else + { + m_Stats.AddValue(Statistic::WalkOneCm, Value); + AddFoodExhaustion(0.0001 * static_cast(Value)); + } } else { diff --git a/src/Mobs/PassiveMonster.cpp b/src/Mobs/PassiveMonster.cpp index f9d5e4ba4..1a8aaa3bf 100644 --- a/src/Mobs/PassiveMonster.cpp +++ b/src/Mobs/PassiveMonster.cpp @@ -57,6 +57,7 @@ void cPassiveMonster::ResetLoveMode() m_LoveTimer = 0; m_MatingTimer = 0; m_LoveCooldown = 20 * 60 * 5; // 5 minutes + m_Feeder = cUUID(); // when an animal is in love mode, the client only stops sending the hearts if we let them know it's in cooldown, which is done with the "age" metadata m_World->BroadcastEntityMetadata(*this); @@ -125,6 +126,15 @@ void cPassiveMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) m_World->SpawnExperienceOrb(Pos.x, Pos.y, Pos.z, GetRandomProvider().RandInt(1, 6)); + m_World->DoWithPlayerByUUID(m_Feeder, [&] (cPlayer & a_Player) + { + a_Player.GetStatManager().AddValue(Statistic::AnimalsBred); + if (GetMobType() == eMonsterType::mtCow) + { + a_Player.AwardAchievement(Statistic::AchBreedCow); + } + return true; + }); m_LovePartner->ResetLoveMode(); ResetLoveMode(); } @@ -241,6 +251,8 @@ void cPassiveMonster::OnRightClicked(cPlayer & a_Player) } } } + // Stores feeder UUID for statistic tracking + m_Feeder = a_Player.GetUUID(); } diff --git a/src/Mobs/PassiveMonster.h b/src/Mobs/PassiveMonster.h index fbe381955..67d7399d8 100644 --- a/src/Mobs/PassiveMonster.h +++ b/src/Mobs/PassiveMonster.h @@ -2,6 +2,7 @@ #pragma once #include "Monster.h" +#include "../UUID.h" @@ -60,6 +61,9 @@ protected: /** The monster's breeding partner. */ cPassiveMonster * m_LovePartner; + /** Remembers the player is was last fed by for statistics tracking */ + cUUID m_Feeder; + /** If above 0, the monster is in love mode, and will breed if a nearby monster is also in love mode. Decrements by 1 per tick till reaching zero. */ int m_LoveTimer; -- cgit v1.2.3