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
@@ -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
View File
@@ -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,
+109 -4
View File
@@ -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);
}
+31 -2
View File
@@ -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()))
+34 -33
View File
@@ -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;
} }