feat(Core/Achievements): Add possibility to complete achievements and update achievement criteria for offline players. (#19851)
This commit is contained in:
committed by
GitHub
parent
221dbd3fdb
commit
9999a80c96
@@ -0,0 +1,10 @@
|
|||||||
|
DROP TABLE IF EXISTS `character_achievement_offline_updates`;
|
||||||
|
CREATE TABLE `character_achievement_offline_updates` (
|
||||||
|
`guid` BIGINT UNSIGNED NOT NULL COMMENT 'Character\'s GUID',
|
||||||
|
`update_type` TINYINT UNSIGNED NOT NULL COMMENT 'Supported types: 1 - COMPLETE_ACHIEVEMENT; 2 - UPDATE_CRITERIA',
|
||||||
|
`arg1` INT UNSIGNED NOT NULL COMMENT 'For type 1: achievement ID; for type 2: ACHIEVEMENT_CRITERIA_TYPE',
|
||||||
|
`arg2` INT UNSIGNED DEFAULT NULL COMMENT 'For type 2: miscValue1 for updating achievement criteria',
|
||||||
|
`arg3` INT UNSIGNED DEFAULT NULL COMMENT 'For type 2: miscValue2 for updating achievement criteria',
|
||||||
|
INDEX `idx_guid` (`guid`)
|
||||||
|
)
|
||||||
|
COMMENT = 'Stores updates to character achievements when the character was offline';
|
||||||
+2
-1
@@ -43,7 +43,8 @@
|
|||||||
#define MAX_NETCLIENT_PACKET_SIZE (32767 - 1) // Client hardcap: int16 with trailing zero space otherwise crash on memory free
|
#define MAX_NETCLIENT_PACKET_SIZE (32767 - 1) // Client hardcap: int16 with trailing zero space otherwise crash on memory free
|
||||||
|
|
||||||
// TimeConstants
|
// TimeConstants
|
||||||
constexpr auto MINUTE = 60;
|
constexpr auto SECOND = 1;
|
||||||
|
constexpr auto MINUTE = SECOND * 60;
|
||||||
constexpr auto HOUR = MINUTE * 60;
|
constexpr auto HOUR = MINUTE * 60;
|
||||||
constexpr auto DAY = HOUR * 24;
|
constexpr auto DAY = HOUR * 24;
|
||||||
constexpr auto WEEK = DAY * 7;
|
constexpr auto WEEK = DAY * 7;
|
||||||
|
|||||||
@@ -441,6 +441,9 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
|||||||
PrepareStatement(CHAR_INS_CHAR_ACHIEVEMENT, "INSERT INTO character_achievement (guid, achievement, date) VALUES (?, ?, ?)", CONNECTION_ASYNC);
|
PrepareStatement(CHAR_INS_CHAR_ACHIEVEMENT, "INSERT INTO character_achievement (guid, achievement, date) VALUES (?, ?, ?)", CONNECTION_ASYNC);
|
||||||
PrepareStatement(CHAR_DEL_CHAR_ACHIEVEMENT_PROGRESS_BY_CRITERIA, "DELETE FROM character_achievement_progress WHERE guid = ? AND criteria = ?", CONNECTION_ASYNC);
|
PrepareStatement(CHAR_DEL_CHAR_ACHIEVEMENT_PROGRESS_BY_CRITERIA, "DELETE FROM character_achievement_progress WHERE guid = ? AND criteria = ?", CONNECTION_ASYNC);
|
||||||
PrepareStatement(CHAR_INS_CHAR_ACHIEVEMENT_PROGRESS, "INSERT INTO character_achievement_progress (guid, criteria, counter, date) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
|
PrepareStatement(CHAR_INS_CHAR_ACHIEVEMENT_PROGRESS, "INSERT INTO character_achievement_progress (guid, criteria, counter, date) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
|
||||||
|
PrepareStatement(CHAR_INS_CHAR_ACHIEVEMENT_OFFLINE_UPDATES, "INSERT INTO character_achievement_offline_updates (guid, update_type, arg1, arg2, arg3) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC);
|
||||||
|
PrepareStatement(CHAR_SEL_CHAR_ACHIEVEMENT_OFFLINE_UPDATES, "SELECT update_type, arg1, arg2, arg3 FROM character_achievement_offline_updates WHERE guid = ?", CONNECTION_ASYNC);
|
||||||
|
PrepareStatement(CHAR_DEL_CHAR_ACHIEVEMENT_OFFLINE_UPDATES, "DELETE FROM character_achievement_offline_updates WHERE guid = ?", CONNECTION_ASYNC);
|
||||||
PrepareStatement(CHAR_DEL_CHAR_REPUTATION_BY_FACTION, "DELETE FROM character_reputation WHERE guid = ? AND faction = ?", CONNECTION_ASYNC);
|
PrepareStatement(CHAR_DEL_CHAR_REPUTATION_BY_FACTION, "DELETE FROM character_reputation WHERE guid = ? AND faction = ?", CONNECTION_ASYNC);
|
||||||
PrepareStatement(CHAR_INS_CHAR_REPUTATION_BY_FACTION, "INSERT INTO character_reputation (guid, faction, standing, flags) VALUES (?, ?, ? , ?)", CONNECTION_ASYNC);
|
PrepareStatement(CHAR_INS_CHAR_REPUTATION_BY_FACTION, "INSERT INTO character_reputation (guid, faction, standing, flags) VALUES (?, ?, ? , ?)", CONNECTION_ASYNC);
|
||||||
PrepareStatement(CHAR_UPD_CHAR_ARENA_POINTS, "UPDATE characters SET arenaPoints = (arenaPoints + ?) WHERE guid = ?", CONNECTION_ASYNC);
|
PrepareStatement(CHAR_UPD_CHAR_ARENA_POINTS, "UPDATE characters SET arenaPoints = (arenaPoints + ?) WHERE guid = ?", CONNECTION_ASYNC);
|
||||||
|
|||||||
@@ -365,6 +365,9 @@ enum CharacterDatabaseStatements : uint32
|
|||||||
CHAR_INS_CHAR_ACHIEVEMENT,
|
CHAR_INS_CHAR_ACHIEVEMENT,
|
||||||
CHAR_DEL_CHAR_ACHIEVEMENT_PROGRESS_BY_CRITERIA,
|
CHAR_DEL_CHAR_ACHIEVEMENT_PROGRESS_BY_CRITERIA,
|
||||||
CHAR_INS_CHAR_ACHIEVEMENT_PROGRESS,
|
CHAR_INS_CHAR_ACHIEVEMENT_PROGRESS,
|
||||||
|
CHAR_INS_CHAR_ACHIEVEMENT_OFFLINE_UPDATES,
|
||||||
|
CHAR_SEL_CHAR_ACHIEVEMENT_OFFLINE_UPDATES,
|
||||||
|
CHAR_DEL_CHAR_ACHIEVEMENT_OFFLINE_UPDATES,
|
||||||
CHAR_DEL_CHAR_REPUTATION_BY_FACTION,
|
CHAR_DEL_CHAR_REPUTATION_BY_FACTION,
|
||||||
CHAR_INS_CHAR_REPUTATION_BY_FACTION,
|
CHAR_INS_CHAR_REPUTATION_BY_FACTION,
|
||||||
CHAR_UPD_CHAR_ARENA_POINTS,
|
CHAR_UPD_CHAR_ARENA_POINTS,
|
||||||
|
|||||||
@@ -481,6 +481,7 @@ bool AchievementCriteriaDataSet::Meets(Player const* source, Unit const* target,
|
|||||||
AchievementMgr::AchievementMgr(Player* player)
|
AchievementMgr::AchievementMgr(Player* player)
|
||||||
{
|
{
|
||||||
_player = player;
|
_player = player;
|
||||||
|
_offlineUpdatesDelayTimer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
AchievementMgr::~AchievementMgr()
|
AchievementMgr::~AchievementMgr()
|
||||||
@@ -550,6 +551,10 @@ void AchievementMgr::DeleteFromDB(ObjectGuid::LowType lowguid)
|
|||||||
stmt->SetData(0, lowguid);
|
stmt->SetData(0, lowguid);
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
|
|
||||||
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENT_OFFLINE_UPDATES);
|
||||||
|
stmt->SetData(0, lowguid);
|
||||||
|
trans->Append(stmt);
|
||||||
|
|
||||||
CharacterDatabase.CommitTransaction(trans);
|
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)
|
if (achievementResult)
|
||||||
{
|
{
|
||||||
@@ -669,6 +674,28 @@ void AchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, PreparedQ
|
|||||||
progress.changed = false;
|
progress.changed = false;
|
||||||
} while (criteriaResult->NextRow());
|
} 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
|
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_NUMBER_OF_TALENT_RESETS:
|
||||||
case ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL:
|
case ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL:
|
||||||
case ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION:
|
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_NEED:
|
||||||
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED:
|
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED:
|
||||||
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_DISENCHANT:
|
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_AT_BARBER:
|
||||||
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL:
|
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL:
|
||||||
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY:
|
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_DAMAGE_RECEIVED:
|
||||||
case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED:
|
case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED:
|
||||||
case ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS:
|
case ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS:
|
||||||
@@ -915,7 +942,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
|
|||||||
break;
|
break;
|
||||||
// std case: high value at miscvalue1
|
// std case: high value at miscvalue1
|
||||||
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID:
|
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_DEALT:
|
||||||
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED:
|
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED:
|
||||||
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CASTED:
|
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CASTED:
|
||||||
@@ -2158,6 +2185,22 @@ void AchievementMgr::RemoveCriteriaProgress(const AchievementCriteriaEntry* entr
|
|||||||
_criteriaProgress.erase(criteriaProgress);
|
_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)
|
void AchievementMgr::UpdateTimedAchievements(uint32 timeDiff)
|
||||||
{
|
{
|
||||||
if (!_timedAchievements.empty())
|
if (!_timedAchievements.empty())
|
||||||
@@ -2437,6 +2480,46 @@ CompletedAchievementMap const& AchievementMgr::GetCompletedAchievements()
|
|||||||
return _completedAchievements;
|
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()
|
AchievementGlobalMgr* AchievementGlobalMgr::instance()
|
||||||
{
|
{
|
||||||
static AchievementGlobalMgr instance;
|
static AchievementGlobalMgr instance;
|
||||||
@@ -3054,3 +3137,25 @@ AchievementEntry const* AchievementGlobalMgr::GetAchievement(uint32 achievementI
|
|||||||
{
|
{
|
||||||
return sAchievementStore.LookupEntry(achievementId);
|
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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -33,6 +33,20 @@ typedef std::list<AchievementEntry const*> AchievementEntryList;
|
|||||||
typedef std::unordered_map<uint32, AchievementCriteriaEntryList> AchievementCriteriaListByAchievement;
|
typedef std::unordered_map<uint32, AchievementCriteriaEntryList> AchievementCriteriaListByAchievement;
|
||||||
typedef std::map<uint32, AchievementEntryList> AchievementListByReferencedId;
|
typedef std::map<uint32, AchievementEntryList> AchievementListByReferencedId;
|
||||||
|
|
||||||
|
enum AchievementOfflinePlayerUpdateType
|
||||||
|
{
|
||||||
|
ACHIEVEMENT_OFFLINE_PLAYER_UPDATE_TYPE_COMPLETE_ACHIEVEMENT = 1,
|
||||||
|
ACHIEVEMENT_OFFLINE_PLAYER_UPDATE_TYPE_UPDATE_CRITERIA = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AchievementOfflinePlayerUpdate
|
||||||
|
{
|
||||||
|
AchievementOfflinePlayerUpdateType updateType;
|
||||||
|
uint32 arg1;
|
||||||
|
uint32 arg2;
|
||||||
|
uint32 arg3;
|
||||||
|
};
|
||||||
|
|
||||||
struct CriteriaProgress
|
struct CriteriaProgress
|
||||||
{
|
{
|
||||||
uint32 counter;
|
uint32 counter;
|
||||||
@@ -284,7 +298,7 @@ public:
|
|||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
static void DeleteFromDB(ObjectGuid::LowType lowguid);
|
static void DeleteFromDB(ObjectGuid::LowType lowguid);
|
||||||
void LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult);
|
void LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult, PreparedQueryResult offlineUpdatesResult);
|
||||||
void SaveToDB(CharacterDatabaseTransaction trans);
|
void SaveToDB(CharacterDatabaseTransaction trans);
|
||||||
void ResetAchievementCriteria(AchievementCriteriaCondition condition, uint32 value, bool evenIfCriteriaComplete = false);
|
void ResetAchievementCriteria(AchievementCriteriaCondition condition, uint32 value, bool evenIfCriteriaComplete = false);
|
||||||
void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscValue1 = 0, uint32 miscValue2 = 0, Unit* unit = nullptr);
|
void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscValue1 = 0, uint32 miscValue2 = 0, Unit* unit = nullptr);
|
||||||
@@ -294,7 +308,8 @@ public:
|
|||||||
void SendRespondInspectAchievements(Player* player) const;
|
void SendRespondInspectAchievements(Player* player) const;
|
||||||
[[nodiscard]] bool HasAchieved(uint32 achievementId) const;
|
[[nodiscard]] bool HasAchieved(uint32 achievementId) const;
|
||||||
[[nodiscard]] Player* GetPlayer() const { return _player; }
|
[[nodiscard]] Player* GetPlayer() const { return _player; }
|
||||||
void UpdateTimedAchievements(uint32 timeDiff);
|
|
||||||
|
void Update(uint32 timeDiff);
|
||||||
void StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry, uint32 timeLost = 0);
|
void StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry, uint32 timeLost = 0);
|
||||||
void RemoveTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry); // used for quest and scripted timed achievements
|
void RemoveTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry); // used for quest and scripted timed achievements
|
||||||
|
|
||||||
@@ -313,11 +328,23 @@ private:
|
|||||||
bool CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement);
|
bool CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement);
|
||||||
void BuildAllDataPacket(WorldPacket* data) const;
|
void BuildAllDataPacket(WorldPacket* data) const;
|
||||||
|
|
||||||
|
void UpdateTimedAchievements(uint32 timeDiff);
|
||||||
|
|
||||||
|
// Handles updates when character was offline.
|
||||||
|
void ProcessOfflineUpdate(AchievementOfflinePlayerUpdate const& update);
|
||||||
|
void ProcessOfflineUpdatesQueue();
|
||||||
|
|
||||||
Player* _player;
|
Player* _player;
|
||||||
CriteriaProgressMap _criteriaProgress;
|
CriteriaProgressMap _criteriaProgress;
|
||||||
CompletedAchievementMap _completedAchievements;
|
CompletedAchievementMap _completedAchievements;
|
||||||
typedef std::map<uint32, uint32> TimedAchievementMap;
|
typedef std::map<uint32, uint32> TimedAchievementMap;
|
||||||
TimedAchievementMap _timedAchievements; // Criteria id/time left in MS
|
TimedAchievementMap _timedAchievements; // Criteria id/time left in MS
|
||||||
|
|
||||||
|
// Offline updates cannot be processed while players are loading,
|
||||||
|
// as the player will not be notified of the changes.
|
||||||
|
// To ensure proper notification, introduce a delay before processing.
|
||||||
|
uint32 _offlineUpdatesDelayTimer;
|
||||||
|
std::vector<AchievementOfflinePlayerUpdate> _offlineUpdatesQueue;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AchievementGlobalMgr
|
class AchievementGlobalMgr
|
||||||
@@ -398,6 +425,8 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] AchievementEntry const* GetAchievement(uint32 achievementId) const;
|
[[nodiscard]] AchievementEntry const* GetAchievement(uint32 achievementId) const;
|
||||||
|
|
||||||
|
void CompletedAchievementForOfflinePlayer(ObjectGuid::LowType playerLowGuid, AchievementEntry const* entry);
|
||||||
|
void UpdateAchievementCriteriaForOfflinePlayer(ObjectGuid::LowType playerLowGuid, AchievementCriteriaTypes type, uint32 miscValue1 = 0, uint32 miscValue2 = 0);
|
||||||
private:
|
private:
|
||||||
AchievementCriteriaDataMap _criteriaDataMap;
|
AchievementCriteriaDataMap _criteriaDataMap;
|
||||||
|
|
||||||
|
|||||||
@@ -318,10 +318,14 @@ void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry* auction, CharacterDatabas
|
|||||||
{
|
{
|
||||||
if (sendNotification) // can be changed in the hook
|
if (sendNotification) // can be changed in the hook
|
||||||
bidder->GetSession()->SendAuctionBidderNotification(auction->GetHouseId(), auction->Id, auction->bidder, 0, 0, auction->item_template);
|
bidder->GetSession()->SendAuctionBidderNotification(auction->GetHouseId(), auction->Id, auction->bidder, 0, 0, auction->item_template);
|
||||||
// FIXME: for offline player need also
|
|
||||||
if (updateAchievementCriteria) // can be changed in the hook
|
if (updateAchievementCriteria) // can be changed in the hook
|
||||||
bidder->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS, 1);
|
bidder->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS, 1);
|
||||||
}
|
}
|
||||||
|
else if (updateAchievementCriteria)
|
||||||
|
{
|
||||||
|
sAchievementMgr->UpdateAchievementCriteriaForOfflinePlayer(auction->bidder.GetCounter(), ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS, 1);
|
||||||
|
}
|
||||||
|
|
||||||
if (sendMail) // can be changed in the hook
|
if (sendMail) // can be changed in the hook
|
||||||
MailDraft(auction->BuildAuctionMailSubject(AUCTION_WON), AuctionEntry::BuildAuctionMailBody(auction->owner, auction->bid, auction->buyout))
|
MailDraft(auction->BuildAuctionMailSubject(AUCTION_WON), AuctionEntry::BuildAuctionMailBody(auction->owner, auction->bid, auction->buyout))
|
||||||
@@ -375,6 +379,11 @@ void AuctionHouseMgr::SendAuctionSuccessfulMail(AuctionEntry* auction, Character
|
|||||||
if (sendNotification) // can be changed in the hook
|
if (sendNotification) // can be changed in the hook
|
||||||
owner->GetSession()->SendAuctionOwnerNotification(auction);
|
owner->GetSession()->SendAuctionOwnerNotification(auction);
|
||||||
}
|
}
|
||||||
|
else if (updateAchievementCriteria)
|
||||||
|
{
|
||||||
|
sAchievementMgr->UpdateAchievementCriteriaForOfflinePlayer(auction->owner.GetCounter(), ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS, profit);
|
||||||
|
sAchievementMgr->UpdateAchievementCriteriaForOfflinePlayer(auction->owner.GetCounter(), ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD, auction->bid);
|
||||||
|
}
|
||||||
|
|
||||||
if (sendMail) // can be changed in the hook
|
if (sendMail) // can be changed in the hook
|
||||||
MailDraft(auction->BuildAuctionMailSubject(AUCTION_SUCCESSFUL), AuctionEntry::BuildAuctionMailBody(auction->bidder, auction->bid, auction->buyout, auction->deposit, auction->GetAuctionCut()))
|
MailDraft(auction->BuildAuctionMailSubject(AUCTION_SUCCESSFUL), AuctionEntry::BuildAuctionMailBody(auction->bidder, auction->bid, auction->buyout, auction->deposit, auction->GetAuctionCut()))
|
||||||
|
|||||||
@@ -861,39 +861,40 @@ enum PlayedTimeIndex
|
|||||||
// used at player loading query list preparing, and later result selection
|
// used at player loading query list preparing, and later result selection
|
||||||
enum PlayerLoginQueryIndex
|
enum PlayerLoginQueryIndex
|
||||||
{
|
{
|
||||||
PLAYER_LOGIN_QUERY_LOAD_FROM = 0,
|
PLAYER_LOGIN_QUERY_LOAD_FROM = 0,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_AURAS = 3,
|
PLAYER_LOGIN_QUERY_LOAD_AURAS = 3,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_SPELLS = 4,
|
PLAYER_LOGIN_QUERY_LOAD_SPELLS = 4,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS = 5,
|
PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS = 5,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_DAILY_QUEST_STATUS = 6,
|
PLAYER_LOGIN_QUERY_LOAD_DAILY_QUEST_STATUS = 6,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_REPUTATION = 7,
|
PLAYER_LOGIN_QUERY_LOAD_REPUTATION = 7,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_INVENTORY = 8,
|
PLAYER_LOGIN_QUERY_LOAD_INVENTORY = 8,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_ACTIONS = 9,
|
PLAYER_LOGIN_QUERY_LOAD_ACTIONS = 9,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_MAILS = 10,
|
PLAYER_LOGIN_QUERY_LOAD_MAILS = 10,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS = 11,
|
PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS = 11,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_SOCIAL_LIST = 13,
|
PLAYER_LOGIN_QUERY_LOAD_SOCIAL_LIST = 13,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_HOME_BIND = 14,
|
PLAYER_LOGIN_QUERY_LOAD_HOME_BIND = 14,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS = 15,
|
PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS = 15,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES = 16,
|
PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES = 16,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS = 18,
|
PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS = 18,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS = 19,
|
PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS = 19,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS = 20,
|
PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS = 20,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_ENTRY_POINT = 21,
|
PLAYER_LOGIN_QUERY_LOAD_ENTRY_POINT = 21,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_GLYPHS = 22,
|
PLAYER_LOGIN_QUERY_LOAD_GLYPHS = 22,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_TALENTS = 23,
|
PLAYER_LOGIN_QUERY_LOAD_TALENTS = 23,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_ACCOUNT_DATA = 24,
|
PLAYER_LOGIN_QUERY_LOAD_ACCOUNT_DATA = 24,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_SKILLS = 25,
|
PLAYER_LOGIN_QUERY_LOAD_SKILLS = 25,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_WEEKLY_QUEST_STATUS = 26,
|
PLAYER_LOGIN_QUERY_LOAD_WEEKLY_QUEST_STATUS = 26,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_RANDOM_BG = 27,
|
PLAYER_LOGIN_QUERY_LOAD_RANDOM_BG = 27,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_BANNED = 28,
|
PLAYER_LOGIN_QUERY_LOAD_BANNED = 28,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_REW = 29,
|
PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_REW = 29,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES = 30,
|
PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES = 30,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_SEASONAL_QUEST_STATUS = 31,
|
PLAYER_LOGIN_QUERY_LOAD_SEASONAL_QUEST_STATUS = 31,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_MONTHLY_QUEST_STATUS = 32,
|
PLAYER_LOGIN_QUERY_LOAD_MONTHLY_QUEST_STATUS = 32,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_BREW_OF_THE_MONTH = 34,
|
PLAYER_LOGIN_QUERY_LOAD_BREW_OF_THE_MONTH = 34,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_CORPSE_LOCATION = 35,
|
PLAYER_LOGIN_QUERY_LOAD_CORPSE_LOCATION = 35,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_CHARACTER_SETTINGS = 36,
|
PLAYER_LOGIN_QUERY_LOAD_CHARACTER_SETTINGS = 36,
|
||||||
PLAYER_LOGIN_QUERY_LOAD_PET_SLOTS = 37,
|
PLAYER_LOGIN_QUERY_LOAD_PET_SLOTS = 37,
|
||||||
|
PLAYER_LOGIN_QUERY_LOAD_OFFLINE_ACHIEVEMENTS_UPDATES = 38,
|
||||||
MAX_PLAYER_LOGIN_QUERY
|
MAX_PLAYER_LOGIN_QUERY
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5023,7 +5023,7 @@ bool Player::LoadFromDB(ObjectGuid playerGuid, CharacterDatabaseQueryHolder cons
|
|||||||
SetCreationTime(fields[74].Get<Seconds>());
|
SetCreationTime(fields[74].Get<Seconds>());
|
||||||
|
|
||||||
// load achievements before anything else to prevent multiple gains for the same achievement/criteria on every loading (as loading does call UpdateAchievementCriteria)
|
// load achievements before anything else to prevent multiple gains for the same achievement/criteria on every loading (as loading does call UpdateAchievementCriteria)
|
||||||
m_achievementMgr->LoadFromDB(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS), holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS));
|
m_achievementMgr->LoadFromDB(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS), holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS), holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_OFFLINE_ACHIEVEMENTS_UPDATES));
|
||||||
|
|
||||||
uint32 money = fields[8].Get<uint32>();
|
uint32 money = fields[8].Get<uint32>();
|
||||||
if (money > MAX_MONEY_AMOUNT)
|
if (money > MAX_MONEY_AMOUNT)
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ void Player::Update(uint32 p_time)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_achievementMgr->UpdateTimedAchievements(p_time);
|
m_achievementMgr->Update(p_time);
|
||||||
|
|
||||||
if (HasUnitState(UNIT_STATE_MELEE_ATTACKING) && !HasUnitState(UNIT_STATE_CASTING) && !HasUnitState(UNIT_STATE_CHARGING))
|
if (HasUnitState(UNIT_STATE_MELEE_ATTACKING) && !HasUnitState(UNIT_STATE_CASTING) && !HasUnitState(UNIT_STATE_CHARGING))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -216,6 +216,10 @@ bool LoginQueryHolder::Initialize()
|
|||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, lowGuid);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_PET_SLOTS, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_PET_SLOTS, stmt);
|
||||||
|
|
||||||
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_ACHIEVEMENT_OFFLINE_UPDATES);
|
||||||
|
stmt->SetData(0, lowGuid);
|
||||||
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_OFFLINE_ACHIEVEMENTS_UPDATES, stmt);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user