Add Statistics and Achievements for newer Network standards
This commit is contained in:
parent
47f7727b7f
commit
7d0813ce8c
@ -206,7 +206,7 @@ void cBeaconEntity::UpdateBeacon(void)
|
||||
(std::abs(Distance.z) <= 20)
|
||||
)
|
||||
{
|
||||
a_Player.AwardAchievement(eStatistic::achFullBeacon);
|
||||
a_Player.AwardAchievement(Statistic::AchFullBeacon);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -544,7 +544,7 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
}
|
||||
}
|
||||
|
||||
Player->GetStatManager().AddValue(statDamageDealt, static_cast<StatValue>(floor(a_TDI.FinalDamage * 10 + 0.5)));
|
||||
Player->GetStatManager().AddValue(Statistic::DamageDealt, FloorC<cStatManager::StatValue>(a_TDI.FinalDamage * 10 + 0.5));
|
||||
}
|
||||
|
||||
m_Health -= a_TDI.FinalDamage;
|
||||
@ -1426,7 +1426,7 @@ bool cEntity::DetectPortal()
|
||||
{
|
||||
if (DestionationDim == dimNether)
|
||||
{
|
||||
static_cast<cPlayer *>(this)->AwardAchievement(achEnterPortal);
|
||||
static_cast<cPlayer *>(this)->AwardAchievement(Statistic::AchPortal);
|
||||
}
|
||||
|
||||
static_cast<cPlayer *>(this)->GetClientHandle()->SendRespawn(DestionationDim);
|
||||
@ -1505,7 +1505,7 @@ bool cEntity::DetectPortal()
|
||||
{
|
||||
if (DestionationDim == dimEnd)
|
||||
{
|
||||
static_cast<cPlayer *>(this)->AwardAchievement(achEnterTheEnd);
|
||||
static_cast<cPlayer *>(this)->AwardAchievement(Statistic::AchTheEnd);
|
||||
}
|
||||
static_cast<cPlayer *>(this)->GetClientHandle()->SendRespawn(DestionationDim);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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<StatValue>(a_Items.Size()));
|
||||
m_Stats.AddValue(Statistic::Drop, static_cast<cStatManager::StatValue>(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<cPawn*>(a_TDI.Attacker), true);
|
||||
}
|
||||
}
|
||||
m_Stats.AddValue(statDamageTaken, FloorC<StatValue>(a_TDI.FinalDamage * 10 + 0.5));
|
||||
m_Stats.AddValue(Statistic::DamageTaken, FloorC<cStatManager::StatValue>(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<StatValue>(Pickups.Size()));
|
||||
m_Stats.AddValue(Statistic::Drop, static_cast<cStatManager::StatValue>(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<cMonster *>(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<unsigned int>(m_Stats.AddValue(a_Ach));
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
if (m_World->ShouldBroadcastAchievementMessages())
|
||||
{
|
||||
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<unsigned int>(New);
|
||||
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<StatValue>(a_DeltaPos.Length() * 100 + 0.5);
|
||||
const auto Value = FloorC<cStatManager::StatValue>(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<StatValue>(a_DeltaPos.y * 100 + 0.5));
|
||||
m_Stats.AddValue(Statistic::ClimbOneCm, FloorC<cStatManager::StatValue>(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<double>(Value));
|
||||
}
|
||||
else if (IsOnGround())
|
||||
{
|
||||
m_Stats.AddValue(statDistWalked, Value);
|
||||
m_Stats.AddValue(Statistic::WalkOneCm, Value);
|
||||
AddFoodExhaustion((IsSprinting() ? 0.001 : 0.0001) * static_cast<double>(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<double>(Value));
|
||||
}
|
||||
else if (a_DeltaPos.y < 0.0)
|
||||
{
|
||||
// Increment statistic
|
||||
m_Stats.AddValue(statDistFallen, static_cast<StatValue>(std::abs(a_DeltaPos.y) * 100 + 0.5));
|
||||
m_Stats.AddValue(Statistic::FallOneCm, static_cast<cStatManager::StatValue>(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<cMonster *>(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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -210,7 +210,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
a_Player.GetStatManager().AddValue(statTreasureFished, 1);
|
||||
a_Player.GetStatManager().AddValue(Statistic::TreasureFished, 1);
|
||||
}
|
||||
else if (ItemCategory < JunkChances[LotSLevel])
|
||||
{
|
||||
@ -262,7 +262,7 @@ public:
|
||||
Drops.Add(cItem(E_BLOCK_TRIPWIRE_HOOK));
|
||||
}
|
||||
|
||||
a_Player.GetStatManager().AddValue(statJunkFished, 1);
|
||||
a_Player.GetStatManager().AddValue(Statistic::JunkFished, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -284,7 +284,7 @@ public:
|
||||
Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_FISH));
|
||||
}
|
||||
|
||||
a_Player.GetStatManager().AddValue(statFishCaught, 1);
|
||||
a_Player.GetStatManager().AddValue(Statistic::FishCaught, 1);
|
||||
}
|
||||
|
||||
// Check with plugins if this loot is acceptable:
|
||||
|
@ -292,7 +292,7 @@ public:
|
||||
double Dist = (a_Player.GetPosition() - Pos).Length();
|
||||
if (Dist < 50.0)
|
||||
{
|
||||
a_Player.AwardAchievement(achSpawnWither);
|
||||
a_Player.AwardAchievement(Statistic::AchSpawnWither);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ void cWither::KilledBy(TakeDamageInfo & a_TDI)
|
||||
if (Dist < 50.0)
|
||||
{
|
||||
// If player is close, award achievement
|
||||
a_Player.AwardAchievement(achKillWither);
|
||||
a_Player.AwardAchievement(Statistic::AchKillWither);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
namespace Palette_1_13
|
||||
{
|
||||
UInt32 FromBlock(short ID)
|
||||
UInt32 FromBlock(const short ID)
|
||||
{
|
||||
using namespace Block;
|
||||
|
||||
@ -7067,7 +7067,7 @@ namespace Palette_1_13
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 FromItem(Item ID)
|
||||
UInt32 FromItem(const Item ID)
|
||||
{
|
||||
switch (ID)
|
||||
{
|
||||
@ -7860,7 +7860,67 @@ namespace Palette_1_13
|
||||
}
|
||||
}
|
||||
|
||||
Item ToItem(UInt32 ID)
|
||||
UInt32 From(const Statistic ID)
|
||||
{
|
||||
switch (ID)
|
||||
{
|
||||
case Statistic::AnimalsBred: return 25;
|
||||
case Statistic::AviateOneCm: return 17;
|
||||
case Statistic::BoatOneCm: return 14;
|
||||
case Statistic::CleanArmor: return 33;
|
||||
case Statistic::CleanBanner: return 34;
|
||||
case Statistic::ClimbOneCm: return 10;
|
||||
case Statistic::CrouchOneCm: return 6;
|
||||
case Statistic::DamageDealt: return 21;
|
||||
case Statistic::DamageTaken: return 22;
|
||||
case Statistic::Deaths: return 23;
|
||||
case Statistic::Drop: return 20;
|
||||
case Statistic::EatCakeSlice: return 30;
|
||||
case Statistic::EnchantItem: return 45;
|
||||
case Statistic::FallOneCm: return 9;
|
||||
case Statistic::FillCauldron: return 31;
|
||||
case Statistic::FishCaught: return 27;
|
||||
case Statistic::FlyOneCm: return 11;
|
||||
case Statistic::HorseOneCm: return 16;
|
||||
case Statistic::InspectDispenser: return 39;
|
||||
case Statistic::InspectDropper: return 37;
|
||||
case Statistic::InspectHopper: return 38;
|
||||
case Statistic::InteractWithBeacon: return 36;
|
||||
case Statistic::InteractWithBrewingstand: return 35;
|
||||
case Statistic::InteractWithCraftingTable: return 48;
|
||||
case Statistic::InteractWithFurnace: return 47;
|
||||
case Statistic::Jump: return 19;
|
||||
case Statistic::LeaveGame: return 0;
|
||||
case Statistic::MinecartOneCm: return 13;
|
||||
case Statistic::MobKills: return 24;
|
||||
case Statistic::OpenChest: return 49;
|
||||
case Statistic::OpenEnderchest: return 44;
|
||||
case Statistic::OpenShulkerBox: return 51;
|
||||
case Statistic::PigOneCm: return 15;
|
||||
case Statistic::PlayerKills: return 26;
|
||||
case Statistic::PlayNoteblock: return 40;
|
||||
case Statistic::PlayOneMinute: return 1;
|
||||
case Statistic::PlayRecord: return 46;
|
||||
case Statistic::PotFlower: return 42;
|
||||
case Statistic::SleepInBed: return 50;
|
||||
case Statistic::SneakTime: return 4;
|
||||
case Statistic::SprintOneCm: return 7;
|
||||
case Statistic::SwimOneCm: return 8;
|
||||
case Statistic::TalkedToVillager: return 28;
|
||||
case Statistic::TimeSinceDeath: return 2;
|
||||
case Statistic::TimeSinceRest: return 3;
|
||||
case Statistic::TradedWithVillager: return 29;
|
||||
case Statistic::TriggerTrappedChest: return 43;
|
||||
case Statistic::TuneNoteblock: return 41;
|
||||
case Statistic::UseCauldron: return 32;
|
||||
case Statistic::WalkOneCm: return 5;
|
||||
case Statistic::WalkOnWaterOneCm: return 18;
|
||||
case Statistic::WalkUnderWaterOneCm: return 12;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
Item ToItem(const UInt32 ID)
|
||||
{
|
||||
switch (ID)
|
||||
{
|
||||
|
@ -1,10 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../Registries/Items.h"
|
||||
#include "../../Registries/Statistics.h"
|
||||
|
||||
namespace Palette_1_13
|
||||
{
|
||||
UInt32 FromBlock(short ID);
|
||||
UInt32 FromItem(Item ID);
|
||||
UInt32 From(Statistic ID);
|
||||
Item ToItem(UInt32 ID);
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
namespace Palette_1_13_1
|
||||
{
|
||||
UInt32 FromBlock(short ID)
|
||||
UInt32 FromBlock(const short ID)
|
||||
{
|
||||
using namespace Block;
|
||||
|
||||
@ -7072,7 +7072,7 @@ namespace Palette_1_13_1
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 FromItem(Item ID)
|
||||
UInt32 FromItem(const Item ID)
|
||||
{
|
||||
switch (ID)
|
||||
{
|
||||
@ -7870,7 +7870,73 @@ namespace Palette_1_13_1
|
||||
}
|
||||
}
|
||||
|
||||
Item ToItem(UInt32 ID)
|
||||
UInt32 From(const Statistic ID)
|
||||
{
|
||||
switch (ID)
|
||||
{
|
||||
case Statistic::AnimalsBred: return 30;
|
||||
case Statistic::AviateOneCm: return 17;
|
||||
case Statistic::BoatOneCm: return 14;
|
||||
case Statistic::CleanArmor: return 38;
|
||||
case Statistic::CleanBanner: return 39;
|
||||
case Statistic::CleanShulkerBox: return 40;
|
||||
case Statistic::ClimbOneCm: return 10;
|
||||
case Statistic::CrouchOneCm: return 6;
|
||||
case Statistic::DamageAbsorbed: return 26;
|
||||
case Statistic::DamageBlockedByShield: return 25;
|
||||
case Statistic::DamageDealt: return 21;
|
||||
case Statistic::DamageDealtAbsorbed: return 22;
|
||||
case Statistic::DamageDealtResisted: return 23;
|
||||
case Statistic::DamageResisted: return 27;
|
||||
case Statistic::DamageTaken: return 24;
|
||||
case Statistic::Deaths: return 28;
|
||||
case Statistic::Drop: return 20;
|
||||
case Statistic::EatCakeSlice: return 35;
|
||||
case Statistic::EnchantItem: return 51;
|
||||
case Statistic::FallOneCm: return 9;
|
||||
case Statistic::FillCauldron: return 36;
|
||||
case Statistic::FishCaught: return 32;
|
||||
case Statistic::FlyOneCm: return 11;
|
||||
case Statistic::HorseOneCm: return 16;
|
||||
case Statistic::InspectDispenser: return 45;
|
||||
case Statistic::InspectDropper: return 43;
|
||||
case Statistic::InspectHopper: return 44;
|
||||
case Statistic::InteractWithBeacon: return 42;
|
||||
case Statistic::InteractWithBrewingstand: return 41;
|
||||
case Statistic::InteractWithCraftingTable: return 54;
|
||||
case Statistic::InteractWithFurnace: return 53;
|
||||
case Statistic::Jump: return 19;
|
||||
case Statistic::LeaveGame: return 0;
|
||||
case Statistic::MinecartOneCm: return 13;
|
||||
case Statistic::MobKills: return 29;
|
||||
case Statistic::OpenChest: return 55;
|
||||
case Statistic::OpenEnderchest: return 50;
|
||||
case Statistic::OpenShulkerBox: return 57;
|
||||
case Statistic::PigOneCm: return 15;
|
||||
case Statistic::PlayerKills: return 31;
|
||||
case Statistic::PlayNoteblock: return 46;
|
||||
case Statistic::PlayOneMinute: return 1;
|
||||
case Statistic::PlayRecord: return 52;
|
||||
case Statistic::PotFlower: return 48;
|
||||
case Statistic::SleepInBed: return 56;
|
||||
case Statistic::SneakTime: return 4;
|
||||
case Statistic::SprintOneCm: return 7;
|
||||
case Statistic::SwimOneCm: return 8;
|
||||
case Statistic::TalkedToVillager: return 33;
|
||||
case Statistic::TimeSinceDeath: return 2;
|
||||
case Statistic::TimeSinceRest: return 3;
|
||||
case Statistic::TradedWithVillager: return 34;
|
||||
case Statistic::TriggerTrappedChest: return 49;
|
||||
case Statistic::TuneNoteblock: return 47;
|
||||
case Statistic::UseCauldron: return 37;
|
||||
case Statistic::WalkOneCm: return 5;
|
||||
case Statistic::WalkOnWaterOneCm: return 18;
|
||||
case Statistic::WalkUnderWaterOneCm: return 12;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
Item ToItem(const UInt32 ID)
|
||||
{
|
||||
switch (ID)
|
||||
{
|
||||
|
@ -1,10 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../Registries/Items.h"
|
||||
#include "../../Registries/Statistics.h"
|
||||
|
||||
namespace Palette_1_13_1
|
||||
{
|
||||
UInt32 FromBlock(short ID);
|
||||
UInt32 FromItem(Item ID);
|
||||
UInt32 From(Statistic ID);
|
||||
Item ToItem(UInt32 ID);
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
namespace Palette_1_14
|
||||
{
|
||||
UInt32 FromBlock(short ID)
|
||||
UInt32 FromBlock(const short ID)
|
||||
{
|
||||
using namespace Block;
|
||||
|
||||
@ -8620,7 +8620,7 @@ namespace Palette_1_14
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 FromItem(Item ID)
|
||||
UInt32 FromItem(const Item ID)
|
||||
{
|
||||
switch (ID)
|
||||
{
|
||||
@ -9505,7 +9505,84 @@ namespace Palette_1_14
|
||||
}
|
||||
}
|
||||
|
||||
Item ToItem(UInt32 ID)
|
||||
UInt32 From(const Statistic ID)
|
||||
{
|
||||
switch (ID)
|
||||
{
|
||||
case Statistic::AnimalsBred: return 30;
|
||||
case Statistic::AviateOneCm: return 17;
|
||||
case Statistic::BellRing: return 66;
|
||||
case Statistic::BoatOneCm: return 14;
|
||||
case Statistic::CleanArmor: return 38;
|
||||
case Statistic::CleanBanner: return 39;
|
||||
case Statistic::CleanShulkerBox: return 40;
|
||||
case Statistic::ClimbOneCm: return 10;
|
||||
case Statistic::CrouchOneCm: return 6;
|
||||
case Statistic::DamageAbsorbed: return 26;
|
||||
case Statistic::DamageBlockedByShield: return 25;
|
||||
case Statistic::DamageDealt: return 21;
|
||||
case Statistic::DamageDealtAbsorbed: return 22;
|
||||
case Statistic::DamageDealtResisted: return 23;
|
||||
case Statistic::DamageResisted: return 27;
|
||||
case Statistic::DamageTaken: return 24;
|
||||
case Statistic::Deaths: return 28;
|
||||
case Statistic::Drop: return 20;
|
||||
case Statistic::EatCakeSlice: return 35;
|
||||
case Statistic::EnchantItem: return 51;
|
||||
case Statistic::FallOneCm: return 9;
|
||||
case Statistic::FillCauldron: return 36;
|
||||
case Statistic::FishCaught: return 32;
|
||||
case Statistic::FlyOneCm: return 11;
|
||||
case Statistic::HorseOneCm: return 16;
|
||||
case Statistic::InspectDispenser: return 45;
|
||||
case Statistic::InspectDropper: return 43;
|
||||
case Statistic::InspectHopper: return 44;
|
||||
case Statistic::InteractWithBeacon: return 42;
|
||||
case Statistic::InteractWithBlastFurnace: return 59;
|
||||
case Statistic::InteractWithBrewingstand: return 41;
|
||||
case Statistic::InteractWithCampfire: return 62;
|
||||
case Statistic::InteractWithCartographyTable: return 63;
|
||||
case Statistic::InteractWithCraftingTable: return 54;
|
||||
case Statistic::InteractWithFurnace: return 53;
|
||||
case Statistic::InteractWithLectern: return 61;
|
||||
case Statistic::InteractWithLoom: return 64;
|
||||
case Statistic::InteractWithSmoker: return 60;
|
||||
case Statistic::InteractWithStonecutter: return 65;
|
||||
case Statistic::Jump: return 19;
|
||||
case Statistic::LeaveGame: return 0;
|
||||
case Statistic::MinecartOneCm: return 13;
|
||||
case Statistic::MobKills: return 29;
|
||||
case Statistic::OpenBarrel: return 58;
|
||||
case Statistic::OpenChest: return 55;
|
||||
case Statistic::OpenEnderchest: return 50;
|
||||
case Statistic::OpenShulkerBox: return 57;
|
||||
case Statistic::PigOneCm: return 15;
|
||||
case Statistic::PlayerKills: return 31;
|
||||
case Statistic::PlayNoteblock: return 46;
|
||||
case Statistic::PlayOneMinute: return 1;
|
||||
case Statistic::PlayRecord: return 52;
|
||||
case Statistic::PotFlower: return 48;
|
||||
case Statistic::RaidTrigger: return 67;
|
||||
case Statistic::RaidWin: return 68;
|
||||
case Statistic::SleepInBed: return 56;
|
||||
case Statistic::SneakTime: return 4;
|
||||
case Statistic::SprintOneCm: return 7;
|
||||
case Statistic::SwimOneCm: return 18;
|
||||
case Statistic::TalkedToVillager: return 33;
|
||||
case Statistic::TimeSinceDeath: return 2;
|
||||
case Statistic::TimeSinceRest: return 3;
|
||||
case Statistic::TradedWithVillager: return 34;
|
||||
case Statistic::TriggerTrappedChest: return 49;
|
||||
case Statistic::TuneNoteblock: return 47;
|
||||
case Statistic::UseCauldron: return 37;
|
||||
case Statistic::WalkOneCm: return 5;
|
||||
case Statistic::WalkOnWaterOneCm: return 8;
|
||||
case Statistic::WalkUnderWaterOneCm: return 12;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
Item ToItem(const UInt32 ID)
|
||||
{
|
||||
switch (ID)
|
||||
{
|
||||
|
@ -1,10 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../Registries/Items.h"
|
||||
#include "../../Registries/Statistics.h"
|
||||
|
||||
namespace Palette_1_14
|
||||
{
|
||||
UInt32 FromBlock(short ID);
|
||||
UInt32 FromItem(Item ID);
|
||||
UInt32 From(Statistic ID);
|
||||
Item ToItem(UInt32 ID);
|
||||
}
|
||||
|
@ -155,7 +155,45 @@ void cProtocol_1_13::SendScoreboardObjective(const AString & a_Name, const AStri
|
||||
|
||||
void cProtocol_1_13::SendStatistics(const cStatManager & a_Manager)
|
||||
{
|
||||
// TODO
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
UInt32 Size = 0;
|
||||
a_Manager.ForEachStatisticType([this, &Size](const auto & Store)
|
||||
{
|
||||
for (const auto & Item : Store)
|
||||
{
|
||||
// Client balks at out-of-range values so there is no good default value
|
||||
// We're forced to not send the statistics this protocol version doesn't support
|
||||
|
||||
if (GetProtocolStatisticType(Item.first) != static_cast<UInt32>(-1))
|
||||
{
|
||||
Size++;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// No need to check Size != 0
|
||||
// Assume that the vast majority of the time there's at least one statistic to send
|
||||
|
||||
cPacketizer Pkt(*this, pktStatistics);
|
||||
Pkt.WriteVarInt32(Size);
|
||||
|
||||
a_Manager.ForEachStatisticType([this, &Pkt](const cStatManager::CustomStore & Store)
|
||||
{
|
||||
for (const auto & Item : Store)
|
||||
{
|
||||
const auto ID = GetProtocolStatisticType(Item.first);
|
||||
if (ID == static_cast<UInt32>(-1))
|
||||
{
|
||||
// Unsupported, don't send:
|
||||
continue;
|
||||
}
|
||||
|
||||
Pkt.WriteVarInt32(8); // "Custom" category
|
||||
Pkt.WriteVarInt32(ID);
|
||||
Pkt.WriteVarInt32(static_cast<UInt32>(Item.second));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -563,6 +601,15 @@ UInt32 cProtocol_1_13::GetProtocolIDFromItem(short a_ItemID, short a_ItemDamage)
|
||||
|
||||
|
||||
|
||||
UInt32 cProtocol_1_13::GetProtocolStatisticType(Statistic a_Statistic)
|
||||
{
|
||||
return Palette_1_13::From(a_Statistic);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cProtocol_1_13::ReadItem(cByteBuffer & a_ByteBuffer, cItem & a_Item, size_t a_KeepRemainingBytes)
|
||||
{
|
||||
HANDLE_PACKET_READ(a_ByteBuffer, ReadBEInt16, Int16, ItemID);
|
||||
@ -1210,6 +1257,15 @@ UInt32 cProtocol_1_13_1::GetProtocolIDFromItem(short a_ItemID, short a_ItemDamag
|
||||
|
||||
|
||||
|
||||
UInt32 cProtocol_1_13_1::GetProtocolStatisticType(Statistic a_Statistic)
|
||||
{
|
||||
return Palette_1_13_1::From(a_Statistic);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cProtocol_1_13_2:
|
||||
|
||||
|
@ -79,6 +79,7 @@ protected:
|
||||
virtual UInt8 GetEntityMetadataID(eEntityMetadataType a_FieldType);
|
||||
virtual std::pair<short, short> GetItemFromProtocolID(UInt32 a_ProtocolID);
|
||||
virtual UInt32 GetProtocolIDFromItem(short a_ItemID, short a_ItemDamage);
|
||||
virtual UInt32 GetProtocolStatisticType(Statistic a_Statistic);
|
||||
|
||||
virtual bool HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType) override;
|
||||
virtual void HandlePacketPluginMessage(cByteBuffer & a_ByteBuffer) override;
|
||||
@ -111,6 +112,7 @@ protected:
|
||||
virtual Version GetProtocolVersion() override;
|
||||
virtual std::pair<short, short> GetItemFromProtocolID(UInt32 a_ProtocolID) override;
|
||||
virtual UInt32 GetProtocolIDFromItem(short a_ItemID, short a_ItemDamage) override;
|
||||
virtual UInt32 GetProtocolStatisticType(Statistic a_Statistic) override;
|
||||
};
|
||||
|
||||
|
||||
|
@ -303,3 +303,12 @@ UInt32 cProtocol_1_14::GetProtocolIDFromItem(short a_ItemID, short a_ItemDamage)
|
||||
{
|
||||
return Palette_1_14::FromItem(PaletteUpgrade::FromItem(a_ItemID, a_ItemDamage));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
UInt32 cProtocol_1_14::GetProtocolStatisticType(Statistic a_Statistic)
|
||||
{
|
||||
return Palette_1_14::From(a_Statistic);
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ protected:
|
||||
|
||||
virtual std::pair<short, short> GetItemFromProtocolID(UInt32 a_ProtocolID) override;
|
||||
virtual UInt32 GetProtocolIDFromItem(short a_ItemID, short a_ItemDamage) override;
|
||||
virtual UInt32 GetProtocolStatisticType(Statistic a_Statistic) override;
|
||||
|
||||
virtual void WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity) override {}
|
||||
virtual void WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob) override {}
|
||||
|
@ -19,7 +19,6 @@ Implements the 1.8 protocol classes:
|
||||
#include "../EffectID.h"
|
||||
#include "../StringCompression.h"
|
||||
#include "../CompositeChat.h"
|
||||
#include "../Statistics.h"
|
||||
#include "../UUID.h"
|
||||
#include "../World.h"
|
||||
#include "../JsonUtils.h"
|
||||
@ -1421,18 +1420,26 @@ void cProtocol_1_8_0::SendStatistics(const cStatManager & a_Manager)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, pktStatistics);
|
||||
Pkt.WriteVarInt32(statCount); // TODO 2014-05-11 xdot: Optimization: Send "dirty" statistics only
|
||||
|
||||
size_t Count = static_cast<size_t>(statCount);
|
||||
for (size_t i = 0; i < Count; ++i)
|
||||
UInt32 Size = 0;
|
||||
a_Manager.ForEachStatisticType([&Size](const auto & Store)
|
||||
{
|
||||
StatValue Value = a_Manager.GetValue(static_cast<eStatistic>(i));
|
||||
const AString & StatName = cStatInfo::GetName(static_cast<eStatistic>(i));
|
||||
Size += static_cast<UInt32>(Store.size());
|
||||
});
|
||||
|
||||
Pkt.WriteString(StatName);
|
||||
Pkt.WriteVarInt32(static_cast<UInt32>(Value));
|
||||
}
|
||||
// No need to check Size != 0
|
||||
// Assume that the vast majority of the time there's at least one statistic to send
|
||||
|
||||
cPacketizer Pkt(*this, pktStatistics);
|
||||
Pkt.WriteVarInt32(Size);
|
||||
|
||||
a_Manager.ForEachStatisticType([&Pkt](const cStatManager::CustomStore & Store)
|
||||
{
|
||||
for (const auto & Item : Store)
|
||||
{
|
||||
Pkt.WriteString(GetProtocolStatisticName(Item.first));
|
||||
Pkt.WriteVarInt32(static_cast<UInt32>(Item.second));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -2565,7 +2572,7 @@ void cProtocol_1_8_0::HandlePacketClientStatus(cByteBuffer & a_ByteBuffer)
|
||||
case 2:
|
||||
{
|
||||
// Open Inventory achievement
|
||||
m_Client->GetPlayer()->AwardAchievement(achOpenInv);
|
||||
m_Client->GetPlayer()->AwardAchievement(Statistic::AchOpenInventory);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -3968,3 +3975,104 @@ UInt8 cProtocol_1_8_0::GetProtocolEntityType(const cEntity & a_Entity)
|
||||
}
|
||||
UNREACHABLE("Unhandled entity kind");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const char * cProtocol_1_8_0::GetProtocolStatisticName(Statistic a_Statistic)
|
||||
{
|
||||
switch (a_Statistic)
|
||||
{
|
||||
// V1.8 Achievements
|
||||
case Statistic::AchOpenInventory: return "achievement.openInventory";
|
||||
case Statistic::AchMineWood: return "achievement.mineWood";
|
||||
case Statistic::AchBuildWorkBench: return "achievement.buildWorkBench";
|
||||
case Statistic::AchBuildPickaxe: return "achievement.buildPickaxe";
|
||||
case Statistic::AchBuildFurnace: return "achievement.buildFurnace";
|
||||
case Statistic::AchAcquireIron: return "achievement.acquireIron";
|
||||
case Statistic::AchBuildHoe: return "achievement.buildHoe";
|
||||
case Statistic::AchMakeBread: return "achievement.makeBread";
|
||||
case Statistic::AchBakeCake: return "achievement.bakeCake";
|
||||
case Statistic::AchBuildBetterPickaxe: return "achievement.buildBetterPickaxe";
|
||||
case Statistic::AchCookFish: return "achievement.cookFish";
|
||||
case Statistic::AchOnARail: return "achievement.onARail";
|
||||
case Statistic::AchBuildSword: return "achievement.buildSword";
|
||||
case Statistic::AchKillEnemy: return "achievement.killEnemy";
|
||||
case Statistic::AchKillCow: return "achievement.killCow";
|
||||
case Statistic::AchFlyPig: return "achievement.flyPig";
|
||||
case Statistic::AchSnipeSkeleton: return "achievement.snipeSkeleton";
|
||||
case Statistic::AchDiamonds: return "achievement.diamonds";
|
||||
case Statistic::AchPortal: return "achievement.portal";
|
||||
case Statistic::AchGhast: return "achievement.ghast";
|
||||
case Statistic::AchBlazeRod: return "achievement.blazeRod";
|
||||
case Statistic::AchPotion: return "achievement.potion";
|
||||
case Statistic::AchTheEnd: return "achievement.theEnd";
|
||||
case Statistic::AchTheEnd2: return "achievement.theEnd2";
|
||||
case Statistic::AchEnchantments: return "achievement.enchantments";
|
||||
case Statistic::AchOverkill: return "achievement.overkill";
|
||||
case Statistic::AchBookcase: return "achievement.bookcase";
|
||||
case Statistic::AchExploreAllBiomes: return "achievement.exploreAllBiomes";
|
||||
case Statistic::AchSpawnWither: return "achievement.spawnWither";
|
||||
case Statistic::AchKillWither: return "achievement.killWither";
|
||||
case Statistic::AchFullBeacon: return "achievement.fullBeacon";
|
||||
case Statistic::AchBreedCow: return "achievement.breedCow";
|
||||
case Statistic::AchDiamondsToYou: return "achievement.diamondsToYou";
|
||||
|
||||
// V1.8 stats
|
||||
case Statistic::AnimalsBred: return "stat.animalsBred";
|
||||
case Statistic::BoatOneCm: return "stat.boatOneCm";
|
||||
case Statistic::ClimbOneCm: return "stat.climbOneCm";
|
||||
case Statistic::CrouchOneCm: return "stat.crouchOneCm";
|
||||
case Statistic::DamageDealt: return "stat.damageDealt";
|
||||
case Statistic::DamageTaken: return "stat.damageTaken";
|
||||
case Statistic::Deaths: return "stat.deaths";
|
||||
case Statistic::Drop: return "stat.drop";
|
||||
case Statistic::FallOneCm: return "stat.fallOneCm";
|
||||
case Statistic::FishCaught: return "stat.fishCaught";
|
||||
case Statistic::FlyOneCm: return "stat.flyOneCm";
|
||||
case Statistic::HorseOneCm: return "stat.horseOneCm";
|
||||
case Statistic::Jump: return "stat.jump";
|
||||
case Statistic::LeaveGame: return "stat.leaveGame";
|
||||
case Statistic::MinecartOneCm: return "stat.minecartOneCm";
|
||||
case Statistic::MobKills: return "stat.mobKills";
|
||||
case Statistic::PigOneCm: return "stat.pigOneCm";
|
||||
case Statistic::PlayerKills: return "stat.playerKills";
|
||||
case Statistic::PlayOneMinute: return "stat.playOneMinute";
|
||||
case Statistic::SprintOneCm: return "stat.sprintOneCm";
|
||||
case Statistic::SwimOneCm: return "stat.swimOneCm";
|
||||
case Statistic::TalkedToVillager: return "stat.talkedToVillager";
|
||||
case Statistic::TimeSinceDeath: return "stat.timeSinceDeath";
|
||||
case Statistic::TradedWithVillager: return "stat.tradedWithVillager";
|
||||
case Statistic::WalkOneCm: return "stat.walkOneCm";
|
||||
case Statistic::WalkUnderWaterOneCm: return "stat.diveOneCm";
|
||||
|
||||
// V1.8.2 stats
|
||||
case Statistic::CleanArmor: return "stat.armorCleaned";
|
||||
case Statistic::CleanBanner: return "stat.bannerCleaned";
|
||||
case Statistic::EatCakeSlice: return "stat.cakeSlicesEaten";
|
||||
case Statistic::EnchantItem: return "stat.itemEnchanted";
|
||||
case Statistic::FillCauldron: return "stat.cauldronFilled";
|
||||
case Statistic::InspectDispenser: return "stat.dispenserInspected";
|
||||
case Statistic::InspectDropper: return "stat.dropperInspected";
|
||||
case Statistic::InspectHopper: return "stat.hopperInspected";
|
||||
case Statistic::InteractWithBeacon: return "stat.beaconInteraction";
|
||||
case Statistic::InteractWithBrewingstand: return "stat.brewingstandInteraction";
|
||||
case Statistic::InteractWithCraftingTable: return "stat.craftingTableInteraction";
|
||||
case Statistic::InteractWithFurnace: return "stat.furnaceInteraction";
|
||||
case Statistic::OpenChest: return "stat.chestOpened";
|
||||
case Statistic::OpenEnderchest: return "stat.enderchestOpened";
|
||||
case Statistic::PlayNoteblock: return "stat.noteblockPlayed";
|
||||
case Statistic::PlayRecord: return "stat.recordPlayed";
|
||||
case Statistic::PotFlower: return "stat.flowerPotted";
|
||||
case Statistic::TriggerTrappedChest: return "stat.trappedChestTriggered";
|
||||
case Statistic::TuneNoteblock: return "stat.noteblockTuned";
|
||||
case Statistic::UseCauldron: return "stat.cauldronUsed";
|
||||
|
||||
// V1.9 stats
|
||||
case Statistic::AviateOneCm: return "stat.aviateOneCm";
|
||||
case Statistic::SleepInBed: return "stat.sleepInBed";
|
||||
case Statistic::SneakTime: return "stat.sneakTime";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ Declares the 1.8 protocol classes:
|
||||
|
||||
#include "Protocol.h"
|
||||
#include "../ByteBuffer.h"
|
||||
#include "../Registries/Statistics.h"
|
||||
|
||||
#include "../mbedTLS++/AesCfb128Decryptor.h"
|
||||
#include "../mbedTLS++/AesCfb128Encryptor.h"
|
||||
@ -254,5 +255,10 @@ private:
|
||||
|
||||
/** Converts an entity to a protocol-specific entity type.
|
||||
Only entities that the Send Spawn Entity packet supports are valid inputs to this method */
|
||||
UInt8 GetProtocolEntityType(const cEntity & a_Entity);
|
||||
static UInt8 GetProtocolEntityType(const cEntity & a_Entity);
|
||||
|
||||
/** Converts a statistic to a protocol-specific string.
|
||||
Protocols <= 1.12 use strings, hence this is a static as the string-mapping was append-only for the versions that used it.
|
||||
Returns an empty string, handled correctly by the client, for newer, unsupported statistics. */
|
||||
static const char * GetProtocolStatisticName(Statistic a_Statistic);
|
||||
} ;
|
||||
|
@ -24,7 +24,6 @@ Implements the 1.9 protocol classes:
|
||||
#include "../World.h"
|
||||
#include "../StringCompression.h"
|
||||
#include "../CompositeChat.h"
|
||||
#include "../Statistics.h"
|
||||
#include "../JsonUtils.h"
|
||||
|
||||
#include "../WorldStorage/FastNBT.h"
|
||||
|
@ -5,4 +5,5 @@ target_sources(
|
||||
|
||||
Blocks.h
|
||||
Items.h
|
||||
Statistics.h
|
||||
)
|
120
src/Registries/Statistics.h
Normal file
120
src/Registries/Statistics.h
Normal file
@ -0,0 +1,120 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
enum class Statistic
|
||||
{
|
||||
/* Achievements */
|
||||
AchOpenInventory, /* Taking Inventory */
|
||||
AchMineWood, /* Getting Wood */
|
||||
AchBuildWorkBench, /* Benchmarking */
|
||||
AchBuildPickaxe, /* Time to Mine! */
|
||||
AchBuildFurnace, /* Hot Topic */
|
||||
AchAcquireIron, /* Acquire Hardware */
|
||||
AchBuildHoe, /* Time to Farm! */
|
||||
AchMakeBread, /* Bake Bread */
|
||||
AchBakeCake, /* The Lie */
|
||||
AchBuildBetterPickaxe, /* Getting an Upgrade */
|
||||
AchCookFish, /* Delicious Fish */
|
||||
AchOnARail, /* On A Rail */
|
||||
AchBuildSword, /* Time to Strike! */
|
||||
AchKillEnemy, /* Monster Hunter */
|
||||
AchKillCow, /* Cow Tipper */
|
||||
AchFlyPig, /* When Pigs Fly */
|
||||
AchSnipeSkeleton, /* Sniper Duel */
|
||||
AchDiamonds, /* DIAMONDS! */
|
||||
AchPortal, /* We Need to Go Deeper */
|
||||
AchGhast, /* Return to Sender */
|
||||
AchBlazeRod, /* Into Fire */
|
||||
AchPotion, /* Local Brewery */
|
||||
AchTheEnd, /* The End? */
|
||||
AchTheEnd2, /* The End. */
|
||||
AchEnchantments, /* Enchanter */
|
||||
AchOverkill, /* Overkill */
|
||||
AchBookcase, /* Librarian */
|
||||
AchExploreAllBiomes, /* Adventuring Time */
|
||||
AchSpawnWither, /* The Beginning? */
|
||||
AchKillWither, /* The Beginning. */
|
||||
AchFullBeacon, /* Beaconator */
|
||||
AchBreedCow, /* Repopulation */
|
||||
AchDiamondsToYou, /* Diamonds to you! */
|
||||
|
||||
/* Statistics */
|
||||
AnimalsBred,
|
||||
AviateOneCm,
|
||||
BellRing,
|
||||
BoatOneCm,
|
||||
CleanArmor,
|
||||
CleanBanner,
|
||||
CleanShulkerBox,
|
||||
ClimbOneCm,
|
||||
CrouchOneCm,
|
||||
DamageAbsorbed,
|
||||
DamageBlockedByShield,
|
||||
DamageDealt,
|
||||
DamageDealtAbsorbed,
|
||||
DamageDealtResisted,
|
||||
DamageResisted,
|
||||
DamageTaken,
|
||||
Deaths,
|
||||
Drop,
|
||||
EatCakeSlice,
|
||||
EnchantItem,
|
||||
FallOneCm,
|
||||
FillCauldron,
|
||||
FishCaught,
|
||||
FlyOneCm,
|
||||
HorseOneCm,
|
||||
InspectDispenser,
|
||||
InspectDropper,
|
||||
InspectHopper,
|
||||
InteractWithAnvil,
|
||||
InteractWithBeacon,
|
||||
InteractWithBlastFurnace,
|
||||
InteractWithBrewingstand,
|
||||
InteractWithCampfire,
|
||||
InteractWithCartographyTable,
|
||||
InteractWithCraftingTable,
|
||||
InteractWithFurnace,
|
||||
InteractWithGrindstone,
|
||||
InteractWithLectern,
|
||||
InteractWithLoom,
|
||||
InteractWithSmithingTable,
|
||||
InteractWithSmoker,
|
||||
InteractWithStonecutter,
|
||||
Jump,
|
||||
LeaveGame,
|
||||
MinecartOneCm,
|
||||
MobKills,
|
||||
OpenBarrel,
|
||||
OpenChest,
|
||||
OpenEnderchest,
|
||||
OpenShulkerBox,
|
||||
PigOneCm,
|
||||
PlayNoteblock,
|
||||
PlayOneMinute,
|
||||
PlayRecord,
|
||||
PlayerKills,
|
||||
PotFlower,
|
||||
RaidTrigger,
|
||||
RaidWin,
|
||||
SleepInBed,
|
||||
SneakTime,
|
||||
SprintOneCm,
|
||||
StriderOneCm,
|
||||
SwimOneCm,
|
||||
TalkedToVillager,
|
||||
TargetHit,
|
||||
TimeSinceDeath,
|
||||
TimeSinceRest,
|
||||
TradedWithVillager,
|
||||
TriggerTrappedChest,
|
||||
TuneNoteblock,
|
||||
UseCauldron,
|
||||
WalkOnWaterOneCm,
|
||||
WalkOneCm,
|
||||
WalkUnderWaterOneCm,
|
||||
|
||||
// Old ones just for compatibility
|
||||
JunkFished,
|
||||
TreasureFished,
|
||||
};
|
@ -6,199 +6,78 @@
|
||||
#include "Statistics.h"
|
||||
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wglobal-constructors"
|
||||
#endif
|
||||
|
||||
cStatInfo cStatInfo::ms_Info[statCount] =
|
||||
|
||||
|
||||
void cStatManager::SetValue(const Statistic a_Stat, const StatValue a_Value)
|
||||
{
|
||||
// The order must match the order of enum eStatistic
|
||||
|
||||
// https://minecraft.gamepedia.com/Achievements
|
||||
|
||||
/* Type | Name | Prerequisite */
|
||||
cStatInfo(achOpenInv, "achievement.openInventory"),
|
||||
cStatInfo(achMineWood, "achievement.mineWood", achOpenInv),
|
||||
cStatInfo(achCraftWorkbench, "achievement.buildWorkBench", achMineWood),
|
||||
cStatInfo(achCraftPickaxe, "achievement.buildPickaxe", achCraftWorkbench),
|
||||
cStatInfo(achCraftFurnace, "achievement.buildFurnace", achCraftPickaxe),
|
||||
cStatInfo(achAcquireIron, "achievement.acquireIron", achCraftFurnace),
|
||||
cStatInfo(achCraftHoe, "achievement.buildHoe", achCraftWorkbench),
|
||||
cStatInfo(achMakeBread, "achievement.makeBread", achCraftHoe),
|
||||
cStatInfo(achBakeCake, "achievement.bakeCake", achCraftHoe),
|
||||
cStatInfo(achCraftBetterPick, "achievement.buildBetterPickaxe", achCraftPickaxe),
|
||||
cStatInfo(achCookFish, "achievement.cookFish", achAcquireIron),
|
||||
cStatInfo(achOnARail, "achievement.onARail", achAcquireIron),
|
||||
cStatInfo(achCraftSword, "achievement.buildSword", achCraftWorkbench),
|
||||
cStatInfo(achKillMonster, "achievement.killEnemy", achCraftSword),
|
||||
cStatInfo(achKillCow, "achievement.killCow", achCraftSword),
|
||||
cStatInfo(achFlyPig, "achievement.flyPig", achKillCow),
|
||||
cStatInfo(achSnipeSkeleton, "achievement.snipeSkeleton", achKillMonster),
|
||||
cStatInfo(achDiamonds, "achievement.diamonds", achAcquireIron),
|
||||
cStatInfo(achEnterPortal, "achievement.portal", achDiamonds),
|
||||
cStatInfo(achReturnToSender, "achievement.ghast", achEnterPortal),
|
||||
cStatInfo(achBlazeRod, "achievement.blazeRod", achEnterPortal),
|
||||
cStatInfo(achBrewPotion, "achievement.potion", achBlazeRod),
|
||||
cStatInfo(achEnterTheEnd, "achievement.theEnd", achBlazeRod),
|
||||
cStatInfo(achDefeatDragon, "achievement.theEnd2", achEnterTheEnd),
|
||||
cStatInfo(achCraftEnchantTable, "achievement.enchantments", achDiamonds),
|
||||
cStatInfo(achOverkill, "achievement.overkill", achCraftEnchantTable),
|
||||
cStatInfo(achBookshelf, "achievement.bookcase", achCraftEnchantTable),
|
||||
cStatInfo(achExploreAllBiomes, "achievement.exploreAllBiomes", achEnterTheEnd),
|
||||
cStatInfo(achSpawnWither, "achievement.spawnWither", achDefeatDragon),
|
||||
cStatInfo(achKillWither, "achievement.killWither", achSpawnWither),
|
||||
cStatInfo(achFullBeacon, "achievement.fullBeacon", achKillWither),
|
||||
cStatInfo(achBreedCow, "achievement.breedCow", achKillCow),
|
||||
cStatInfo(achThrowDiamonds, "achievement.diamondsToYou", achDiamonds),
|
||||
|
||||
// https://minecraft.gamepedia.com/Statistics
|
||||
|
||||
/* Type | Name */
|
||||
cStatInfo(statGamesQuit, "stat.leaveGame"),
|
||||
cStatInfo(statMinutesPlayed, "stat.playOneMinute"),
|
||||
cStatInfo(statDistWalked, "stat.walkOneCm"),
|
||||
cStatInfo(statDistSwum, "stat.swimOneCm"),
|
||||
cStatInfo(statDistFallen, "stat.fallOneCm"),
|
||||
cStatInfo(statDistClimbed, "stat.climbOneCm"),
|
||||
cStatInfo(statDistFlown, "stat.flyOneCm"),
|
||||
cStatInfo(statDistDove, "stat.diveOneCm"),
|
||||
cStatInfo(statDistMinecart, "stat.minecartOneCm"),
|
||||
cStatInfo(statDistBoat, "stat.boatOneCm"),
|
||||
cStatInfo(statDistPig, "stat.pigOneCm"),
|
||||
cStatInfo(statDistHorse, "stat.horseOneCm"),
|
||||
cStatInfo(statJumps, "stat.jump"),
|
||||
cStatInfo(statItemsDropped, "stat.drop"),
|
||||
cStatInfo(statDamageDealt, "stat.damageDealt"),
|
||||
cStatInfo(statDamageTaken, "stat.damageTaken"),
|
||||
cStatInfo(statDeaths, "stat.deaths"),
|
||||
cStatInfo(statMobKills, "stat.mobKills"),
|
||||
cStatInfo(statAnimalsBred, "stat.animalsBred"),
|
||||
cStatInfo(statPlayerKills, "stat.playerKills"),
|
||||
cStatInfo(statFishCaught, "stat.fishCaught"),
|
||||
cStatInfo(statJunkFished, "stat.junkFished"),
|
||||
cStatInfo(statTreasureFished, "stat.treasureFished")
|
||||
};
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cStatInfo::cStatInfo()
|
||||
: m_Type(statInvalid)
|
||||
, m_Depends(statInvalid)
|
||||
{}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cStatInfo::cStatInfo(const eStatistic a_Type, const AString & a_Name, const eStatistic a_Depends)
|
||||
: m_Type(a_Type)
|
||||
, m_Name(a_Name)
|
||||
, m_Depends(a_Depends)
|
||||
{}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const AString & cStatInfo::GetName(const eStatistic a_Type)
|
||||
{
|
||||
ASSERT((a_Type > statInvalid) && (a_Type < statCount));
|
||||
|
||||
return ms_Info[a_Type].m_Name;
|
||||
m_CustomStatistics[a_Stat] = a_Value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
eStatistic cStatInfo::GetType(const AString & a_Name)
|
||||
cStatManager::StatValue cStatManager::AddValue(const Statistic a_Stat, const StatValue a_Delta)
|
||||
{
|
||||
for (unsigned int i = 0; i < ARRAYCOUNT(ms_Info); ++i)
|
||||
return m_CustomStatistics[a_Stat] += a_Delta;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cStatManager::SatisfiesPrerequisite(const Statistic a_Stat)
|
||||
{
|
||||
switch (a_Stat)
|
||||
{
|
||||
if (NoCaseCompare(ms_Info[i].m_Name, a_Name) == 0)
|
||||
{
|
||||
return ms_Info[i].m_Type;
|
||||
}
|
||||
case Statistic::AchMineWood: return IsStatisticPresent(Statistic::AchOpenInventory);
|
||||
case Statistic::AchBuildWorkBench: return IsStatisticPresent(Statistic::AchMineWood);
|
||||
case Statistic::AchBuildHoe: return IsStatisticPresent(Statistic::AchBuildWorkBench);
|
||||
case Statistic::AchBakeCake: return IsStatisticPresent(Statistic::AchBuildHoe);
|
||||
case Statistic::AchMakeBread: return IsStatisticPresent(Statistic::AchBuildHoe);
|
||||
case Statistic::AchBuildSword: return IsStatisticPresent(Statistic::AchBuildWorkBench);
|
||||
case Statistic::AchKillCow: return IsStatisticPresent(Statistic::AchBuildSword);
|
||||
case Statistic::AchFlyPig: return IsStatisticPresent(Statistic::AchKillCow);
|
||||
case Statistic::AchBreedCow: return IsStatisticPresent(Statistic::AchKillCow);
|
||||
case Statistic::AchKillEnemy: return IsStatisticPresent(Statistic::AchBuildSword);
|
||||
case Statistic::AchSnipeSkeleton: return IsStatisticPresent(Statistic::AchKillEnemy);
|
||||
case Statistic::AchBuildPickaxe: return IsStatisticPresent(Statistic::AchBuildWorkBench);
|
||||
case Statistic::AchBuildBetterPickaxe: return IsStatisticPresent(Statistic::AchBuildPickaxe);
|
||||
case Statistic::AchBuildFurnace: return IsStatisticPresent(Statistic::AchBuildWorkBench);
|
||||
case Statistic::AchCookFish: return IsStatisticPresent(Statistic::AchBuildFurnace);
|
||||
case Statistic::AchAcquireIron: return IsStatisticPresent(Statistic::AchBuildFurnace);
|
||||
case Statistic::AchOnARail: return IsStatisticPresent(Statistic::AchAcquireIron);
|
||||
case Statistic::AchDiamonds: return IsStatisticPresent(Statistic::AchAcquireIron);
|
||||
case Statistic::AchPortal: return IsStatisticPresent(Statistic::AchDiamonds);
|
||||
case Statistic::AchGhast: return IsStatisticPresent(Statistic::AchPortal);
|
||||
case Statistic::AchBlazeRod: return IsStatisticPresent(Statistic::AchPortal);
|
||||
case Statistic::AchPotion: return IsStatisticPresent(Statistic::AchBlazeRod);
|
||||
case Statistic::AchTheEnd: return IsStatisticPresent(Statistic::AchBlazeRod);
|
||||
case Statistic::AchTheEnd2: return IsStatisticPresent(Statistic::AchTheEnd);
|
||||
case Statistic::AchEnchantments: return IsStatisticPresent(Statistic::AchDiamonds);
|
||||
case Statistic::AchOverkill: return IsStatisticPresent(Statistic::AchEnchantments);
|
||||
case Statistic::AchBookcase: return IsStatisticPresent(Statistic::AchEnchantments);
|
||||
case Statistic::AchExploreAllBiomes: return IsStatisticPresent(Statistic::AchTheEnd);
|
||||
case Statistic::AchSpawnWither: return IsStatisticPresent(Statistic::AchTheEnd2);
|
||||
case Statistic::AchKillWither: return IsStatisticPresent(Statistic::AchSpawnWither);
|
||||
case Statistic::AchFullBeacon: return IsStatisticPresent(Statistic::AchKillWither);
|
||||
case Statistic::AchDiamondsToYou: return IsStatisticPresent(Statistic::AchDiamonds);
|
||||
}
|
||||
|
||||
return statInvalid;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
eStatistic cStatInfo::GetPrerequisite(const eStatistic a_Type)
|
||||
bool cStatManager::IsStatisticPresent(const Statistic a_Stat) const
|
||||
{
|
||||
ASSERT((a_Type > statInvalid) && (a_Type < statCount));
|
||||
|
||||
return ms_Info[a_Type].m_Depends;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cStatManager::cStatManager()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
StatValue cStatManager::GetValue(const eStatistic a_Stat) const
|
||||
{
|
||||
ASSERT((a_Stat > statInvalid) && (a_Stat < statCount));
|
||||
|
||||
return m_MainStats[a_Stat];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cStatManager::SetValue(const eStatistic a_Stat, const StatValue a_Value)
|
||||
{
|
||||
ASSERT((a_Stat > statInvalid) && (a_Stat < statCount));
|
||||
|
||||
m_MainStats[a_Stat] = a_Value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
StatValue cStatManager::AddValue(const eStatistic a_Stat, const StatValue a_Delta)
|
||||
{
|
||||
ASSERT((a_Stat > statInvalid) && (a_Stat < statCount));
|
||||
|
||||
m_MainStats[a_Stat] += a_Delta;
|
||||
|
||||
return m_MainStats[a_Stat];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cStatManager::Reset(void)
|
||||
{
|
||||
for (unsigned int i = 0; i < static_cast<unsigned int>(statCount); ++i)
|
||||
const auto Result = m_CustomStatistics.find(a_Stat);
|
||||
if (Result != m_CustomStatistics.end())
|
||||
{
|
||||
m_MainStats[i] = 0;
|
||||
return Result->second > 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
167
src/Statistics.h
167
src/Statistics.h
@ -1,162 +1,59 @@
|
||||
|
||||
// Statistics.h
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Registries/Statistics.h"
|
||||
|
||||
/* Hello fellow developer !
|
||||
In case you are trying to add new statistics to Cuberite you need to do a few things:
|
||||
---------------------------------------------------------------------------
|
||||
1. add a new entry to the enum class Statistic in Registries\Statistics.h file
|
||||
2. add this to serialization functions in WorldStorage\NamespaceSerializer.cpp
|
||||
The String in the above is used for saving on disk!
|
||||
so use the same string!
|
||||
|
||||
In case you want to add a mapping of network IDs to the used stats
|
||||
you will find a lua script in ../Tools/BlockTypePaletteGenerator/ExportStatMapping.lua
|
||||
it will provide you with information how to use it. you need a registries.json
|
||||
exported from the server https://wiki.vg/Data_Generators
|
||||
|
||||
// tolua_begin
|
||||
enum eStatistic
|
||||
{
|
||||
// The order must match the order of cStatInfo::ms_Info
|
||||
Greetings 12xx12 */
|
||||
|
||||
statInvalid = -1,
|
||||
|
||||
/* Achievements */
|
||||
achOpenInv, /* Taking Inventory */
|
||||
achMineWood, /* Getting Wood */
|
||||
achCraftWorkbench, /* Benchmarking */
|
||||
achCraftPickaxe, /* Time to Mine! */
|
||||
achCraftFurnace, /* Hot Topic */
|
||||
achAcquireIron, /* Acquire Hardware */
|
||||
achCraftHoe, /* Time to Farm! */
|
||||
achMakeBread, /* Bake Bread */
|
||||
achBakeCake, /* The Lie */
|
||||
achCraftBetterPick, /* Getting an Upgrade */
|
||||
achCookFish, /* Delicious Fish */
|
||||
achOnARail, /* On A Rail */
|
||||
achCraftSword, /* Time to Strike! */
|
||||
achKillMonster, /* Monster Hunter */
|
||||
achKillCow, /* Cow Tipper */
|
||||
achFlyPig, /* When Pigs Fly */
|
||||
achSnipeSkeleton, /* Sniper Duel */
|
||||
achDiamonds, /* DIAMONDS! */
|
||||
achEnterPortal, /* We Need to Go Deeper */
|
||||
achReturnToSender, /* Return to Sender */
|
||||
achBlazeRod, /* Into Fire */
|
||||
achBrewPotion, /* Local Brewery */
|
||||
achEnterTheEnd, /* The End? */
|
||||
achDefeatDragon, /* The End. */
|
||||
achCraftEnchantTable, /* Enchanter */
|
||||
achOverkill, /* Overkill */
|
||||
achBookshelf, /* Librarian */
|
||||
achExploreAllBiomes, /* Adventuring Time */
|
||||
achSpawnWither, /* The Beginning? */
|
||||
achKillWither, /* The Beginning. */
|
||||
achFullBeacon, /* Beaconator */
|
||||
achBreedCow, /* Repopulation */
|
||||
achThrowDiamonds, /* Diamonds to you! */
|
||||
|
||||
/* Statistics */
|
||||
statGamesQuit,
|
||||
statMinutesPlayed,
|
||||
statDistWalked,
|
||||
statDistSwum,
|
||||
statDistFallen,
|
||||
statDistClimbed,
|
||||
statDistFlown,
|
||||
statDistDove,
|
||||
statDistMinecart,
|
||||
statDistBoat,
|
||||
statDistPig,
|
||||
statDistHorse,
|
||||
statJumps,
|
||||
statItemsDropped,
|
||||
statDamageDealt,
|
||||
statDamageTaken,
|
||||
statDeaths,
|
||||
statMobKills,
|
||||
statAnimalsBred,
|
||||
statPlayerKills,
|
||||
statFishCaught,
|
||||
statJunkFished,
|
||||
statTreasureFished,
|
||||
|
||||
statCount
|
||||
};
|
||||
// tolua_end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Class used to store and query statistic-related information. */
|
||||
class cStatInfo
|
||||
{
|
||||
public:
|
||||
|
||||
cStatInfo();
|
||||
|
||||
cStatInfo(const eStatistic a_Type, const AString & a_Name, const eStatistic a_Depends = statInvalid);
|
||||
|
||||
/** Type -> Name */
|
||||
static const AString & GetName(const eStatistic a_Type);
|
||||
|
||||
/** Name -> Type */
|
||||
static eStatistic GetType(const AString & a_Name);
|
||||
|
||||
/** Returns stat prerequisite. (Used for achievements) */
|
||||
static eStatistic GetPrerequisite(const eStatistic a_Type);
|
||||
|
||||
private:
|
||||
|
||||
eStatistic m_Type;
|
||||
|
||||
AString m_Name;
|
||||
|
||||
eStatistic m_Depends;
|
||||
|
||||
static cStatInfo ms_Info[statCount];
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/* Signed (?) integral value. */
|
||||
typedef int StatValue; // tolua_export
|
||||
|
||||
|
||||
|
||||
|
||||
/** Class that manages the statistics and achievements of a single player. */
|
||||
// tolua_begin
|
||||
class cStatManager
|
||||
{
|
||||
public:
|
||||
// tolua_end
|
||||
|
||||
cStatManager();
|
||||
typedef unsigned StatValue;
|
||||
typedef std::unordered_map<Statistic, StatValue> CustomStore;
|
||||
|
||||
// tolua_begin
|
||||
/** Set the value of the specified statistic. */
|
||||
void SetValue(Statistic a_Stat, StatValue a_Value);
|
||||
|
||||
/** Return the value of the specified stat. */
|
||||
StatValue GetValue(const eStatistic a_Stat) const;
|
||||
/** Increments the specified statistic. Returns the new value. */
|
||||
StatValue AddValue(Statistic a_Stat, StatValue a_Delta = 1);
|
||||
|
||||
/** Set the value of the specified stat. */
|
||||
void SetValue(const eStatistic a_Stat, const StatValue a_Value);
|
||||
/** Returns whether the prerequisite for awarding an achievement are satisfied. */
|
||||
bool SatisfiesPrerequisite(Statistic a_Stat);
|
||||
|
||||
/** Reset everything. */
|
||||
void Reset();
|
||||
|
||||
/** Increments the specified stat.
|
||||
Returns the new value.
|
||||
*/
|
||||
StatValue AddValue(const eStatistic a_Stat, const StatValue a_Delta = 1);
|
||||
|
||||
// tolua_end
|
||||
/** Invokes the given callbacks for each category of tracked statistics. */
|
||||
template <class CustomCallback>
|
||||
void ForEachStatisticType(CustomCallback a_Custom) const
|
||||
{
|
||||
a_Custom(m_CustomStatistics);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
StatValue m_MainStats[statCount];
|
||||
|
||||
// TODO 10-05-2014 xdot: Use, mine, craft statistics
|
||||
|
||||
|
||||
}; // tolua_export
|
||||
|
||||
/** Returns if a statistic is both present and has nonzero value. */
|
||||
bool IsStatisticPresent(Statistic a_Stat) const;
|
||||
|
||||
// TODO: Block tallies, entities killed, all the others
|
||||
|
||||
CustomStore m_CustomStatistics;
|
||||
};
|
||||
|
@ -766,16 +766,16 @@ void cSlotAreaCrafting::HandleCraftItem(const cItem & a_Result, cPlayer & a_Play
|
||||
{
|
||||
switch (a_Result.m_ItemType)
|
||||
{
|
||||
case E_BLOCK_WORKBENCH: a_Player.AwardAchievement(achCraftWorkbench); break;
|
||||
case E_BLOCK_FURNACE: a_Player.AwardAchievement(achCraftFurnace); break;
|
||||
case E_BLOCK_CAKE: a_Player.AwardAchievement(achBakeCake); break;
|
||||
case E_BLOCK_ENCHANTMENT_TABLE: a_Player.AwardAchievement(achCraftEnchantTable); break;
|
||||
case E_BLOCK_BOOKCASE: a_Player.AwardAchievement(achBookshelf); break;
|
||||
case E_ITEM_WOODEN_PICKAXE: a_Player.AwardAchievement(achCraftPickaxe); break;
|
||||
case E_ITEM_WOODEN_SWORD: a_Player.AwardAchievement(achCraftSword); break;
|
||||
case E_ITEM_STONE_PICKAXE: a_Player.AwardAchievement(achCraftBetterPick); break;
|
||||
case E_ITEM_WOODEN_HOE: a_Player.AwardAchievement(achCraftHoe); break;
|
||||
case E_ITEM_BREAD: a_Player.AwardAchievement(achMakeBread); break;
|
||||
case E_BLOCK_WORKBENCH: a_Player.AwardAchievement(Statistic::AchBuildWorkBench); break;
|
||||
case E_BLOCK_FURNACE: a_Player.AwardAchievement(Statistic::AchBuildFurnace); break;
|
||||
case E_BLOCK_CAKE: a_Player.AwardAchievement(Statistic::AchBakeCake); break;
|
||||
case E_BLOCK_ENCHANTMENT_TABLE: a_Player.AwardAchievement(Statistic::AchEnchantments); break;
|
||||
case E_BLOCK_BOOKCASE: a_Player.AwardAchievement(Statistic::AchBookcase); break;
|
||||
case E_ITEM_WOODEN_PICKAXE: a_Player.AwardAchievement(Statistic::AchBuildPickaxe); break;
|
||||
case E_ITEM_WOODEN_SWORD: a_Player.AwardAchievement(Statistic::AchBuildSword); break;
|
||||
case E_ITEM_STONE_PICKAXE: a_Player.AwardAchievement(Statistic::AchBuildBetterPickaxe); break;
|
||||
case E_ITEM_WOODEN_HOE: a_Player.AwardAchievement(Statistic::AchBuildHoe); break;
|
||||
case E_ITEM_BREAD: a_Player.AwardAchievement(Statistic::AchMakeBread); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
@ -2043,8 +2043,8 @@ void cSlotAreaFurnace::HandleSmeltItem(const cItem & a_Result, cPlayer & a_Playe
|
||||
/** TODO 2014-05-12 xdot: Figure out when to call this method. */
|
||||
switch (a_Result.m_ItemType)
|
||||
{
|
||||
case E_ITEM_IRON: a_Player.AwardAchievement(achAcquireIron); break;
|
||||
case E_ITEM_COOKED_FISH: a_Player.AwardAchievement(achCookFish); break;
|
||||
case E_ITEM_IRON: a_Player.AwardAchievement(Statistic::AchAcquireIron); break;
|
||||
case E_ITEM_COOKED_FISH: a_Player.AwardAchievement(Statistic::AchCookFish); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
@ -2193,7 +2193,7 @@ void cSlotAreaBrewingstand::HandleBrewedItem(cPlayer & a_Player, const cItem & a
|
||||
// Award an achievement if the item is not a water bottle (is a real brewed potion)
|
||||
if (a_ClickedItem.m_ItemDamage > 0)
|
||||
{
|
||||
a_Player.AwardAchievement(achBrewPotion);
|
||||
a_Player.AwardAchievement(Statistic::AchPotion);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ target_sources(
|
||||
FastNBT.cpp
|
||||
FireworksSerializer.cpp
|
||||
MapSerializer.cpp
|
||||
NamespaceSerializer.cpp
|
||||
NBTChunkSerializer.cpp
|
||||
SchematicFileSerializer.cpp
|
||||
ScoreboardSerializer.cpp
|
||||
@ -16,6 +17,7 @@ target_sources(
|
||||
FastNBT.h
|
||||
FireworksSerializer.h
|
||||
MapSerializer.h
|
||||
NamespaceSerializer.h
|
||||
NBTChunkSerializer.h
|
||||
SchematicFileSerializer.h
|
||||
ScoreboardSerializer.h
|
||||
|
281
src/WorldStorage/NamespaceSerializer.cpp
Normal file
281
src/WorldStorage/NamespaceSerializer.cpp
Normal file
@ -0,0 +1,281 @@
|
||||
#include "Globals.h"
|
||||
|
||||
#include "NamespaceSerializer.h"
|
||||
|
||||
namespace NamespaceSerializer
|
||||
{
|
||||
unsigned DataVersion()
|
||||
{
|
||||
return 2566;
|
||||
}
|
||||
|
||||
const char * From(const Statistic ID)
|
||||
{
|
||||
switch (ID)
|
||||
{
|
||||
case Statistic::AnimalsBred: return "animals_bred";
|
||||
case Statistic::AviateOneCm: return "aviate_one_cm";
|
||||
case Statistic::BellRing: return "bell_ring";
|
||||
case Statistic::BoatOneCm: return "boat_one_cm";
|
||||
case Statistic::CleanArmor: return "clean_armor";
|
||||
case Statistic::CleanBanner: return "clean_banner";
|
||||
case Statistic::CleanShulkerBox: return "clean_shulker_box";
|
||||
case Statistic::ClimbOneCm: return "climb_one_cm";
|
||||
case Statistic::CrouchOneCm: return "crouch_one_cm";
|
||||
case Statistic::DamageAbsorbed: return "damage_absorbed";
|
||||
case Statistic::DamageBlockedByShield: return "damage_blocked_by_shield";
|
||||
case Statistic::DamageDealt: return "damage_dealt";
|
||||
case Statistic::DamageDealtAbsorbed: return "damage_dealt_absorbed";
|
||||
case Statistic::DamageDealtResisted: return "damage_dealt_resisted";
|
||||
case Statistic::DamageResisted: return "damage_resisted";
|
||||
case Statistic::DamageTaken: return "damage_taken";
|
||||
case Statistic::Deaths: return "deaths";
|
||||
case Statistic::Drop: return "drop";
|
||||
case Statistic::EatCakeSlice: return "eat_cake_slice";
|
||||
case Statistic::EnchantItem: return "enchant_item";
|
||||
case Statistic::FallOneCm: return "fall_one_cm";
|
||||
case Statistic::FillCauldron: return "fill_cauldron";
|
||||
case Statistic::FishCaught: return "fish_caught";
|
||||
case Statistic::FlyOneCm: return "fly_one_cm";
|
||||
case Statistic::HorseOneCm: return "horse_one_cm";
|
||||
case Statistic::InspectDispenser: return "inspect_dispenser";
|
||||
case Statistic::InspectDropper: return "inspect_dropper";
|
||||
case Statistic::InspectHopper: return "inspect_hopper";
|
||||
case Statistic::InteractWithAnvil: return "interact_with_anvil";
|
||||
case Statistic::InteractWithBeacon: return "interact_with_beacon";
|
||||
case Statistic::InteractWithBlastFurnace: return "interact_with_blast_furnace";
|
||||
case Statistic::InteractWithBrewingstand: return "interact_with_brewingstand";
|
||||
case Statistic::InteractWithCampfire: return "interact_with_campfire";
|
||||
case Statistic::InteractWithCartographyTable: return "interact_with_cartography_table";
|
||||
case Statistic::InteractWithCraftingTable: return "interact_with_crafting_table";
|
||||
case Statistic::InteractWithFurnace: return "interact_with_furnace";
|
||||
case Statistic::InteractWithGrindstone: return "interact_with_grindstone";
|
||||
case Statistic::InteractWithLectern: return "interact_with_lectern";
|
||||
case Statistic::InteractWithLoom: return "interact_with_loom";
|
||||
case Statistic::InteractWithSmithingTable: return "interact_with_smithing_table";
|
||||
case Statistic::InteractWithSmoker: return "interact_with_smoker";
|
||||
case Statistic::InteractWithStonecutter: return "interact_with_stonecutter";
|
||||
case Statistic::Jump: return "jump";
|
||||
case Statistic::LeaveGame: return "leave_game";
|
||||
case Statistic::MinecartOneCm: return "minecart_one_cm";
|
||||
case Statistic::MobKills: return "mob_kills";
|
||||
case Statistic::OpenBarrel: return "open_barrel";
|
||||
case Statistic::OpenChest: return "open_chest";
|
||||
case Statistic::OpenEnderchest: return "open_enderchest";
|
||||
case Statistic::OpenShulkerBox: return "open_shulker_box";
|
||||
case Statistic::PigOneCm: return "pig_one_cm";
|
||||
case Statistic::PlayNoteblock: return "play_noteblock";
|
||||
case Statistic::PlayOneMinute: return "play_one_minute";
|
||||
case Statistic::PlayRecord: return "play_record";
|
||||
case Statistic::PlayerKills: return "player_kills";
|
||||
case Statistic::PotFlower: return "pot_flower";
|
||||
case Statistic::RaidTrigger: return "raid_trigger";
|
||||
case Statistic::RaidWin: return "raid_win";
|
||||
case Statistic::SleepInBed: return "sleep_in_bed";
|
||||
case Statistic::SneakTime: return "sneak_time";
|
||||
case Statistic::SprintOneCm: return "sprint_one_cm";
|
||||
case Statistic::StriderOneCm: return "strider_one_cm";
|
||||
case Statistic::SwimOneCm: return "swim_one_cm";
|
||||
case Statistic::TalkedToVillager: return "talked_to_villager";
|
||||
case Statistic::TargetHit: return "target_hit";
|
||||
case Statistic::TimeSinceDeath: return "time_since_death";
|
||||
case Statistic::TimeSinceRest: return "time_since_rest";
|
||||
case Statistic::TradedWithVillager: return "traded_with_villager";
|
||||
case Statistic::TriggerTrappedChest: return "trigger_trapped_chest";
|
||||
case Statistic::TuneNoteblock: return "tune_noteblock";
|
||||
case Statistic::UseCauldron: return "use_cauldron";
|
||||
case Statistic::WalkOnWaterOneCm: return "walk_on_water_one_cm";
|
||||
case Statistic::WalkOneCm: return "walk_one_cm";
|
||||
case Statistic::WalkUnderWaterOneCm: return "walk_under_water_one_cm";
|
||||
|
||||
// Old ones just for compatibility
|
||||
case Statistic::JunkFished: return "junk_fished";
|
||||
case Statistic::TreasureFished: return "treasure_fished";
|
||||
|
||||
// The old advancements
|
||||
case Statistic::AchOpenInventory: return "cuberite:achievement.openInventory";
|
||||
case Statistic::AchMineWood: return "cuberite:achievement.mineWood";
|
||||
case Statistic::AchBuildWorkBench: return "cuberite:achievement.buildWorkBench";
|
||||
case Statistic::AchBuildPickaxe: return "cuberite:achievement.buildPickaxe";
|
||||
case Statistic::AchBuildFurnace: return "cuberite:achievement.buildFurnace";
|
||||
case Statistic::AchAcquireIron: return "cuberite:achievement.acquireIron";
|
||||
case Statistic::AchBuildHoe: return "cuberite:achievement.buildHoe";
|
||||
case Statistic::AchMakeBread: return "cuberite:achievement.makeBread";
|
||||
case Statistic::AchBakeCake: return "cuberite:achievement.bakeCake";
|
||||
case Statistic::AchBuildBetterPickaxe: return "cuberite:achievement.buildBetterPickaxe";
|
||||
case Statistic::AchCookFish: return "cuberite:achievement.cookFish";
|
||||
case Statistic::AchOnARail: return "cuberite:achievement.onARail";
|
||||
case Statistic::AchBuildSword: return "cuberite:achievement.buildSword";
|
||||
case Statistic::AchKillEnemy: return "cuberite:achievement.killEnemy";
|
||||
case Statistic::AchKillCow: return "cuberite:achievement.killCow";
|
||||
case Statistic::AchFlyPig: return "cuberite:achievement.flyPig";
|
||||
case Statistic::AchSnipeSkeleton: return "cuberite:achievement.snipeSkeleton";
|
||||
case Statistic::AchDiamonds: return "cuberite:achievement.diamonds";
|
||||
case Statistic::AchPortal: return "cuberite:achievement.portal";
|
||||
case Statistic::AchGhast: return "cuberite:achievement.ghast";
|
||||
case Statistic::AchBlazeRod: return "cuberite:achievement.blazeRod";
|
||||
case Statistic::AchPotion: return "cuberite:achievement.potion";
|
||||
case Statistic::AchTheEnd: return "cuberite:achievement.theEnd";
|
||||
case Statistic::AchTheEnd2: return "cuberite:achievement.theEnd2";
|
||||
case Statistic::AchEnchantments: return "cuberite:achievement.enchantments";
|
||||
case Statistic::AchOverkill: return "cuberite:achievement.overkill";
|
||||
case Statistic::AchBookcase: return "cuberite:achievement.bookcase";
|
||||
case Statistic::AchExploreAllBiomes: return "cuberite:achievement.exploreAllBiomes";
|
||||
case Statistic::AchSpawnWither: return "cuberite:achievement.spawnWither";
|
||||
case Statistic::AchKillWither: return "cuberite:achievement.killWither";
|
||||
case Statistic::AchFullBeacon: return "cuberite:achievement.fullBeacon";
|
||||
case Statistic::AchBreedCow: return "cuberite:achievement.breedCow";
|
||||
case Statistic::AchDiamondsToYou: return "cuberite:achievement.diamondsToYou";
|
||||
}
|
||||
|
||||
UNREACHABLE("Tried to save unhandled statistic");
|
||||
}
|
||||
|
||||
static const std::unordered_map<std::string_view, Statistic> CustomStatistics
|
||||
{
|
||||
{ "animals_bred", Statistic::AnimalsBred },
|
||||
{ "aviate_one_cm", Statistic::AviateOneCm },
|
||||
{ "bell_ring", Statistic::BellRing },
|
||||
{ "boat_one_cm", Statistic::BoatOneCm },
|
||||
{ "clean_armor", Statistic::CleanArmor },
|
||||
{ "clean_banner", Statistic::CleanBanner },
|
||||
{ "clean_shulker_box", Statistic::CleanShulkerBox },
|
||||
{ "climb_one_cm", Statistic::ClimbOneCm },
|
||||
{ "crouch_one_cm", Statistic::CrouchOneCm },
|
||||
{ "damage_absorbed", Statistic::DamageAbsorbed },
|
||||
{ "damage_blocked_by_shield", Statistic::DamageBlockedByShield },
|
||||
{ "damage_dealt", Statistic::DamageDealt },
|
||||
{ "damage_dealt_absorbed", Statistic::DamageDealtAbsorbed },
|
||||
{ "damage_dealt_resisted", Statistic::DamageDealtResisted },
|
||||
{ "damage_resisted", Statistic::DamageResisted },
|
||||
{ "damage_taken", Statistic::DamageTaken },
|
||||
{ "deaths", Statistic::Deaths },
|
||||
{ "drop", Statistic::Drop },
|
||||
{ "eat_cake_slice", Statistic::EatCakeSlice },
|
||||
{ "enchant_item", Statistic::EnchantItem },
|
||||
{ "fall_one_cm", Statistic::FallOneCm },
|
||||
{ "fill_cauldron", Statistic::FillCauldron },
|
||||
{ "fish_caught", Statistic::FishCaught },
|
||||
{ "fly_one_cm", Statistic::FlyOneCm },
|
||||
{ "horse_one_cm", Statistic::HorseOneCm },
|
||||
{ "inspect_dispenser", Statistic::InspectDispenser },
|
||||
{ "inspect_dropper", Statistic::InspectDropper },
|
||||
{ "inspect_hopper", Statistic::InspectHopper },
|
||||
{ "interact_with_anvil", Statistic::InteractWithAnvil },
|
||||
{ "interact_with_beacon", Statistic::InteractWithBeacon },
|
||||
{ "interact_with_blast_furnace", Statistic::InteractWithBlastFurnace },
|
||||
{ "interact_with_brewingstand", Statistic::InteractWithBrewingstand },
|
||||
{ "interact_with_campfire", Statistic::InteractWithCampfire },
|
||||
{ "interact_with_cartography_table", Statistic::InteractWithCartographyTable },
|
||||
{ "interact_with_crafting_table", Statistic::InteractWithCraftingTable },
|
||||
{ "interact_with_furnace", Statistic::InteractWithFurnace },
|
||||
{ "interact_with_grindstone", Statistic::InteractWithGrindstone },
|
||||
{ "interact_with_lectern", Statistic::InteractWithLectern },
|
||||
{ "interact_with_loom", Statistic::InteractWithLoom },
|
||||
{ "interact_with_smithing_table", Statistic::InteractWithSmithingTable },
|
||||
{ "interact_with_smoker", Statistic::InteractWithSmoker },
|
||||
{ "interact_with_stonecutter", Statistic::InteractWithStonecutter },
|
||||
{ "jump", Statistic::Jump },
|
||||
{ "leave_game", Statistic::LeaveGame },
|
||||
{ "minecart_one_cm", Statistic::MinecartOneCm },
|
||||
{ "mob_kills", Statistic::MobKills },
|
||||
{ "open_barrel", Statistic::OpenBarrel },
|
||||
{ "open_chest", Statistic::OpenChest },
|
||||
{ "open_enderchest", Statistic::OpenEnderchest },
|
||||
{ "open_shulker_box", Statistic::OpenShulkerBox },
|
||||
{ "pig_one_cm", Statistic::PigOneCm },
|
||||
{ "play_noteblock", Statistic::PlayNoteblock },
|
||||
{ "play_one_minute", Statistic::PlayOneMinute },
|
||||
{ "play_record", Statistic::PlayRecord },
|
||||
{ "player_kills", Statistic::PlayerKills },
|
||||
{ "pot_flower", Statistic::PotFlower },
|
||||
{ "raid_trigger", Statistic::RaidTrigger },
|
||||
{ "raid_win", Statistic::RaidWin },
|
||||
{ "sleep_in_bed", Statistic::SleepInBed },
|
||||
{ "sneak_time", Statistic::SneakTime },
|
||||
{ "sprint_one_cm", Statistic::SprintOneCm },
|
||||
{ "strider_one_cm", Statistic::StriderOneCm },
|
||||
{ "swim_one_cm", Statistic::SwimOneCm },
|
||||
{ "talked_to_villager", Statistic::TalkedToVillager },
|
||||
{ "target_hit", Statistic::TargetHit },
|
||||
{ "time_since_death", Statistic::TimeSinceDeath },
|
||||
{ "time_since_rest", Statistic::TimeSinceRest },
|
||||
{ "traded_with_villager", Statistic::TradedWithVillager },
|
||||
{ "trigger_trapped_chest", Statistic::TriggerTrappedChest },
|
||||
{ "tune_noteblock", Statistic::TuneNoteblock },
|
||||
{ "use_cauldron", Statistic::UseCauldron },
|
||||
{ "walk_on_water_one_cm", Statistic::WalkOnWaterOneCm },
|
||||
{ "walk_one_cm", Statistic::WalkOneCm },
|
||||
{ "walk_under_water_one_cm", Statistic::WalkUnderWaterOneCm },
|
||||
|
||||
// Old ones just for compatibility
|
||||
{ "junk_fished", Statistic::JunkFished },
|
||||
{ "treasure_fished", Statistic::TreasureFished },
|
||||
|
||||
// The old advancements
|
||||
{ "cuberite:achievement.openInventory", Statistic::AchOpenInventory },
|
||||
{ "cuberite:achievement.mineWood", Statistic::AchMineWood },
|
||||
{ "cuberite:achievement.buildWorkBench", Statistic::AchBuildWorkBench },
|
||||
{ "cuberite:achievement.buildPickaxe", Statistic::AchBuildPickaxe },
|
||||
{ "cuberite:achievement.buildFurnace", Statistic::AchBuildFurnace },
|
||||
{ "cuberite:achievement.acquireIron", Statistic::AchAcquireIron },
|
||||
{ "cuberite:achievement.buildHoe", Statistic::AchBuildHoe },
|
||||
{ "cuberite:achievement.makeBread", Statistic::AchMakeBread },
|
||||
{ "cuberite:achievement.bakeCake", Statistic::AchBakeCake },
|
||||
{ "cuberite:achievement.buildBetterPickaxe", Statistic::AchBuildBetterPickaxe },
|
||||
{ "cuberite:achievement.cookFish", Statistic::AchCookFish },
|
||||
{ "cuberite:achievement.onARail", Statistic::AchOnARail },
|
||||
{ "cuberite:achievement.buildSword", Statistic::AchBuildSword },
|
||||
{ "cuberite:achievement.killEnemy", Statistic::AchKillEnemy },
|
||||
{ "cuberite:achievement.killCow", Statistic::AchKillCow },
|
||||
{ "cuberite:achievement.flyPig", Statistic::AchFlyPig },
|
||||
{ "cuberite:achievement.snipeSkeleton", Statistic::AchSnipeSkeleton },
|
||||
{ "cuberite:achievement.diamonds", Statistic::AchDiamonds },
|
||||
{ "cuberite:achievement.portal", Statistic::AchPortal },
|
||||
{ "cuberite:achievement.ghast", Statistic::AchGhast },
|
||||
{ "cuberite:achievement.blazeRod", Statistic::AchBlazeRod },
|
||||
{ "cuberite:achievement.potion", Statistic::AchPotion },
|
||||
{ "cuberite:achievement.theEnd", Statistic::AchTheEnd },
|
||||
{ "cuberite:achievement.theEnd2", Statistic::AchTheEnd2 },
|
||||
{ "cuberite:achievement.enchantments", Statistic::AchEnchantments },
|
||||
{ "cuberite:achievement.overkill", Statistic::AchOverkill },
|
||||
{ "cuberite:achievement.bookcase", Statistic::AchBookcase },
|
||||
{ "cuberite:achievement.exploreAllBiomes", Statistic::AchExploreAllBiomes },
|
||||
{ "cuberite:achievement.spawnWither", Statistic::AchSpawnWither },
|
||||
{ "cuberite:achievement.killWither", Statistic::AchKillWither },
|
||||
{ "cuberite:achievement.fullBeacon", Statistic::AchFullBeacon },
|
||||
{ "cuberite:achievement.breedCow", Statistic::AchBreedCow },
|
||||
{ "cuberite:achievement.diamondsToYou", Statistic::AchDiamondsToYou}
|
||||
};
|
||||
|
||||
Statistic ToCustomStatistic(const std::string_view ID)
|
||||
{
|
||||
return CustomStatistics.at(ID);
|
||||
}
|
||||
|
||||
std::pair<Namespace, std::string_view> SplitNamespacedID(const std::string_view ID)
|
||||
{
|
||||
const auto NamespaceIndex = ID.find(':');
|
||||
if (NamespaceIndex == std::string_view::npos)
|
||||
{
|
||||
// No explicit namespace default to the Minecraft namespace:
|
||||
return { Namespace::Minecraft, ID };
|
||||
}
|
||||
|
||||
const auto Namespace = ID.substr(0, NamespaceIndex);
|
||||
if (Namespace == "minecraft")
|
||||
{
|
||||
// An unprefixed ID in the vanilla Minecraft namespace
|
||||
const auto Value = ID.substr(NamespaceIndex + 1);
|
||||
|
||||
return { Namespace::Minecraft, Value };
|
||||
}
|
||||
|
||||
if (Namespace == "cuberite")
|
||||
{
|
||||
return { Namespace::Cuberite, ID };
|
||||
}
|
||||
|
||||
return { Namespace::Unknown, ID };
|
||||
}
|
||||
}
|
21
src/WorldStorage/NamespaceSerializer.h
Normal file
21
src/WorldStorage/NamespaceSerializer.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Registries/Statistics.h"
|
||||
|
||||
namespace NamespaceSerializer
|
||||
{
|
||||
enum class Namespace
|
||||
{
|
||||
Minecraft,
|
||||
Cuberite,
|
||||
Unknown
|
||||
};
|
||||
|
||||
unsigned DataVersion();
|
||||
|
||||
const char * From(Statistic ID);
|
||||
|
||||
Statistic ToCustomStatistic(std::string_view ID);
|
||||
|
||||
std::pair<Namespace, std::string_view> SplitNamespacedID(std::string_view ID);
|
||||
}
|
@ -4,15 +4,17 @@
|
||||
|
||||
#include "Globals.h"
|
||||
#include "StatSerializer.h"
|
||||
|
||||
#include "../Statistics.h"
|
||||
#include "../JsonUtils.h"
|
||||
#include "NamespaceSerializer.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <json/json.h>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cStatSerializer::cStatSerializer(const AString & a_WorldName, const AString & a_PlayerName, const AString & a_FileName, cStatManager * a_Manager)
|
||||
cStatSerializer::cStatSerializer(cStatManager & a_Manager, const AString & a_WorldName, const AString & a_FileName)
|
||||
: m_Manager(a_Manager)
|
||||
{
|
||||
// Even though stats are shared between worlds, they are (usually) saved
|
||||
@ -21,8 +23,7 @@ cStatSerializer::cStatSerializer(const AString & a_WorldName, const AString & a_
|
||||
AString StatsPath;
|
||||
Printf(StatsPath, "%s%cstats", a_WorldName.c_str(), cFile::PathSeparator());
|
||||
|
||||
m_LegacyPath = StatsPath + "/" + a_PlayerName + ".json";
|
||||
m_Path = StatsPath + "/" + a_FileName + ".json";
|
||||
m_Path = StatsPath + cFile::PathSeparator() + a_FileName + ".json";
|
||||
|
||||
// Ensure that the directory exists.
|
||||
cFile::CreateFolder(StatsPath);
|
||||
@ -32,49 +33,26 @@ cStatSerializer::cStatSerializer(const AString & a_WorldName, const AString & a_
|
||||
|
||||
|
||||
|
||||
bool cStatSerializer::Load(void)
|
||||
void cStatSerializer::Load(void)
|
||||
{
|
||||
AString Data = cFile::ReadWholeFile(m_Path);
|
||||
if (Data.empty())
|
||||
{
|
||||
Data = cFile::ReadWholeFile(m_LegacyPath);
|
||||
if (Data.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Json::Value Root;
|
||||
std::ifstream(m_Path) >> Root;
|
||||
|
||||
if (JsonUtils::ParseString(Data, Root))
|
||||
{
|
||||
return LoadStatFromJSON(Root);
|
||||
}
|
||||
|
||||
return false;
|
||||
LoadCustomStatFromJSON(Root["stats"]["custom"]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cStatSerializer::Save(void)
|
||||
void cStatSerializer::Save(void)
|
||||
{
|
||||
Json::Value Root;
|
||||
SaveStatToJSON(Root);
|
||||
|
||||
cFile File;
|
||||
if (!File.Open(m_Path, cFile::fmWrite))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
SaveStatToJSON(Root["stats"]);
|
||||
Root["DataVersion"] = NamespaceSerializer::DataVersion();
|
||||
|
||||
AString JsonData = JsonUtils::WriteStyledString(Root);
|
||||
|
||||
File.Write(JsonData.data(), JsonData.size());
|
||||
File.Close();
|
||||
|
||||
return true;
|
||||
std::ofstream(m_Path) << Root;
|
||||
}
|
||||
|
||||
|
||||
@ -83,68 +61,50 @@ bool cStatSerializer::Save(void)
|
||||
|
||||
void cStatSerializer::SaveStatToJSON(Json::Value & a_Out)
|
||||
{
|
||||
for (unsigned int i = 0; i < static_cast<unsigned int>(statCount); ++i)
|
||||
m_Manager.ForEachStatisticType([&a_Out](const cStatManager::CustomStore & Store)
|
||||
{
|
||||
StatValue Value = m_Manager->GetValue(static_cast<eStatistic>(i));
|
||||
|
||||
if (Value != 0)
|
||||
if (Store.empty())
|
||||
{
|
||||
const AString & StatName = cStatInfo::GetName(static_cast<eStatistic>(i));
|
||||
|
||||
a_Out[StatName] = Value;
|
||||
// Avoid saving "custom": null to disk:
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO 2014-05-11 xdot: Save "progress"
|
||||
}
|
||||
auto & Custom = a_Out["custom"];
|
||||
for (const auto & Item : Store)
|
||||
{
|
||||
Custom[NamespaceSerializer::From(Item.first)] = Item.second;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cStatSerializer::LoadStatFromJSON(const Json::Value & a_In)
|
||||
void cStatSerializer::LoadCustomStatFromJSON(const Json::Value & a_In)
|
||||
{
|
||||
m_Manager->Reset();
|
||||
|
||||
for (Json::Value::const_iterator it = a_In.begin() ; it != a_In.end() ; ++it)
|
||||
for (auto it = a_In.begin() ; it != a_In.end() ; ++it)
|
||||
{
|
||||
AString StatName = it.key().asString();
|
||||
|
||||
eStatistic StatType = cStatInfo::GetType(StatName);
|
||||
|
||||
if (StatType == statInvalid)
|
||||
const auto & Key = it.key().asString();
|
||||
const auto StatInfo = NamespaceSerializer::SplitNamespacedID(Key);
|
||||
if (StatInfo.first == NamespaceSerializer::Namespace::Unknown)
|
||||
{
|
||||
LOGWARNING("Invalid statistic type \"%s\"", StatName.c_str());
|
||||
// Ignore non-Vanilla, non-Cuberite namespaces for now:
|
||||
continue;
|
||||
}
|
||||
|
||||
const Json::Value & Node = *it;
|
||||
|
||||
if (Node.isInt())
|
||||
const auto & StatName = StatInfo.second;
|
||||
try
|
||||
{
|
||||
m_Manager->SetValue(StatType, Node.asInt());
|
||||
m_Manager.SetValue(NamespaceSerializer::ToCustomStatistic(StatName), it->asInt());
|
||||
}
|
||||
else if (Node.isObject())
|
||||
catch (const std::out_of_range & Oops)
|
||||
{
|
||||
StatValue Value = Node.get("value", 0).asInt();
|
||||
|
||||
// TODO 2014-05-11 xdot: Load "progress"
|
||||
|
||||
m_Manager->SetValue(StatType, Value);
|
||||
FLOGWARNING("Invalid statistic type \"{}\"", StatName);
|
||||
}
|
||||
else
|
||||
catch (const Json::LogicError & Oops)
|
||||
{
|
||||
LOGWARNING("Invalid statistic value for type \"%s\"", StatName.c_str());
|
||||
FLOGWARNING("Invalid statistic value for type \"{}\"", StatName);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -9,14 +9,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "json/json.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// fwd:
|
||||
class cStatManager;
|
||||
namespace Json { class Value; }
|
||||
|
||||
|
||||
|
||||
|
||||
@ -25,32 +25,21 @@ class cStatSerializer
|
||||
{
|
||||
public:
|
||||
|
||||
cStatSerializer(const AString & a_WorldName, const AString & a_PlayerName, const AString & a_FileName, cStatManager * a_Manager);
|
||||
cStatSerializer(cStatManager & a_Manager, const AString & a_WorldName, const AString & a_FileName);
|
||||
|
||||
/* Try to load the player statistics. Returns whether the operation was successful or not. */
|
||||
bool Load(void);
|
||||
|
||||
/* Try to save the player statistics. Returns whether the operation was successful or not. */
|
||||
bool Save(void);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
void SaveStatToJSON(Json::Value & a_Out);
|
||||
|
||||
bool LoadStatFromJSON(const Json::Value & a_In);
|
||||
/* Try to load the player statistics. */
|
||||
void Load(void);
|
||||
|
||||
/* Try to save the player statistics. */
|
||||
void Save(void);
|
||||
|
||||
private:
|
||||
|
||||
cStatManager * m_Manager;
|
||||
void SaveStatToJSON(Json::Value & a_Out);
|
||||
|
||||
void LoadCustomStatFromJSON(const Json::Value & a_In);
|
||||
|
||||
cStatManager & m_Manager;
|
||||
|
||||
AString m_LegacyPath; // The old <username>.json path to try to read from if the uuid path doesn't exist on load
|
||||
AString m_Path;
|
||||
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user