feat(Core/Achievements): Add possibility to complete achievements and update achievement criteria for offline players. (#19851)

This commit is contained in:
Anton Popovichenko
2024-09-03 18:05:23 +02:00
committed by GitHub
parent 221dbd3fdb
commit 9999a80c96
11 changed files with 208 additions and 43 deletions

View File

@@ -481,6 +481,7 @@ bool AchievementCriteriaDataSet::Meets(Player const* source, Unit const* target,
AchievementMgr::AchievementMgr(Player* player)
{
_player = player;
_offlineUpdatesDelayTimer = 0;
}
AchievementMgr::~AchievementMgr()
@@ -550,6 +551,10 @@ void AchievementMgr::DeleteFromDB(ObjectGuid::LowType lowguid)
stmt->SetData(0, lowguid);
trans->Append(stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENT_OFFLINE_UPDATES);
stmt->SetData(0, lowguid);
trans->Append(stmt);
CharacterDatabase.CommitTransaction(trans);
}
@@ -609,7 +614,7 @@ void AchievementMgr::SaveToDB(CharacterDatabaseTransaction trans)
}
}
void AchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult)
void AchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult, PreparedQueryResult offlineUpdatesResult)
{
if (achievementResult)
{
@@ -669,6 +674,28 @@ void AchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, PreparedQ
progress.changed = false;
} while (criteriaResult->NextRow());
}
if (offlineUpdatesResult)
{
uint32 count = 0;
do
{
Field* fields = offlineUpdatesResult->Fetch();
AchievementOfflinePlayerUpdate update;
update.updateType = static_cast<AchievementOfflinePlayerUpdateType>(fields[0].Get<uint8>());
update.arg1 = fields[1].Get<uint32>();
update.arg2 = fields[2].Get<uint32>();
update.arg3 = fields[3].Get<uint32>();
_offlineUpdatesQueue.push_back(update);
++count;
} while (offlineUpdatesResult->NextRow());
if (count > 0)
_offlineUpdatesDelayTimer = 5 * SECOND * IN_MILLISECONDS;
}
}
void AchievementMgr::SendAchievementEarned(AchievementEntry const* achievement) const
@@ -884,7 +911,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
case ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS:
case ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL:
case ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION:
case ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS: /* FIXME: for online player only currently */
case ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS:
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED:
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED:
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_DISENCHANT:
@@ -904,7 +931,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER:
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL:
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY:
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS:/* FIXME: for online player only currently */
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS:
case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED:
case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED:
case ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS:
@@ -915,7 +942,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
break;
// std case: high value at miscvalue1
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD: /* FIXME: for online player only currently */
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CASTED:
@@ -2158,6 +2185,22 @@ void AchievementMgr::RemoveCriteriaProgress(const AchievementCriteriaEntry* entr
_criteriaProgress.erase(criteriaProgress);
}
void AchievementMgr::Update(uint32 timeDiff)
{
if (_offlineUpdatesDelayTimer > 0)
{
if (timeDiff >= _offlineUpdatesDelayTimer)
{
_offlineUpdatesDelayTimer = 0;
ProcessOfflineUpdatesQueue();
}
else
_offlineUpdatesDelayTimer -= timeDiff;
}
UpdateTimedAchievements(timeDiff);
}
void AchievementMgr::UpdateTimedAchievements(uint32 timeDiff)
{
if (!_timedAchievements.empty())
@@ -2437,6 +2480,46 @@ CompletedAchievementMap const& AchievementMgr::GetCompletedAchievements()
return _completedAchievements;
}
void AchievementMgr::ProcessOfflineUpdatesQueue()
{
if (_offlineUpdatesQueue.empty())
return;
for (auto const& update : _offlineUpdatesQueue)
ProcessOfflineUpdate(update);
_offlineUpdatesQueue.clear();
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENT_OFFLINE_UPDATES);
stmt->SetData(0, GetPlayer()->GetGUID().GetCounter());
CharacterDatabase.Execute(stmt);
}
void AchievementMgr::ProcessOfflineUpdate(AchievementOfflinePlayerUpdate const& update)
{
switch (update.updateType)
{
case ACHIEVEMENT_OFFLINE_PLAYER_UPDATE_TYPE_COMPLETE_ACHIEVEMENT:
{
AchievementEntry const* achievement = sAchievementStore.LookupEntry(update.arg1);
ASSERT(achievement != NULL, "Not found achievement to complete for offline achievements update. Wrong arg1 ({}) value?", update.arg1);
CompletedAchievement(achievement);
break;
}
case ACHIEVEMENT_OFFLINE_PLAYER_UPDATE_TYPE_UPDATE_CRITERIA:
{
AchievementCriteriaTypes criteriaType = static_cast<AchievementCriteriaTypes>(update.arg1);
UpdateAchievementCriteria(criteriaType, update.arg2, update.arg3);
break;
}
default:
ASSERT(false, "Unknown offline achievement update type ({}) for player - {}", update.updateType, GetPlayer()->GetGUID().GetCounter());
break;
}
}
AchievementGlobalMgr* AchievementGlobalMgr::instance()
{
static AchievementGlobalMgr instance;
@@ -3054,3 +3137,25 @@ AchievementEntry const* AchievementGlobalMgr::GetAchievement(uint32 achievementI
{
return sAchievementStore.LookupEntry(achievementId);
}
void AchievementGlobalMgr::CompletedAchievementForOfflinePlayer(ObjectGuid::LowType playerLowGuid, AchievementEntry const* entry)
{
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_ACHIEVEMENT_OFFLINE_UPDATES);
stmt->SetData(0, playerLowGuid);
stmt->SetData(1, uint32(ACHIEVEMENT_OFFLINE_PLAYER_UPDATE_TYPE_COMPLETE_ACHIEVEMENT));
stmt->SetData(2, entry->ID);
stmt->SetData(3, 0);
stmt->SetData(4, 0);
CharacterDatabase.Execute(stmt);
}
void AchievementGlobalMgr::UpdateAchievementCriteriaForOfflinePlayer(ObjectGuid::LowType playerLowGuid, AchievementCriteriaTypes type, uint32 miscValue1, uint32 miscValue2)
{
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_ACHIEVEMENT_OFFLINE_UPDATES);
stmt->SetData(0, playerLowGuid);
stmt->SetData(1, uint32(ACHIEVEMENT_OFFLINE_PLAYER_UPDATE_TYPE_UPDATE_CRITERIA));
stmt->SetData(2, type);
stmt->SetData(3, miscValue1);
stmt->SetData(4, miscValue2);
CharacterDatabase.Execute(stmt);
}