diff options
author | Shauren <shauren.trinity@gmail.com> | 2022-07-03 23:44:48 +0200 |
---|---|---|
committer | Ergar <ergar@gmx.net> | 2025-07-20 17:59:45 +0200 |
commit | cbabaa0f3a605ed8ca0742c1b4a2eb4f741a01a9 (patch) | |
tree | 7de24d88cea3fab709f011c654d17fe97729f3d4 /src | |
parent | 97b16e2eb8c7d28bd954560cede812234932a457 (diff) |
Core/Quests: Reset seasonal quests based on saved completion time and intended holiday start time
(cherry picked from commit 49ad0d2d495a9f817ad2820f8e616f3a6564b480)
Diffstat (limited to 'src')
-rw-r--r-- | src/server/database/Database/Implementation/CharacterDatabase.cpp | 6 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 38 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 8 | ||||
-rw-r--r-- | src/server/game/Events/GameEventMgr.cpp | 17 | ||||
-rw-r--r-- | src/server/game/Events/GameEventMgr.h | 1 | ||||
-rw-r--r-- | src/server/game/World/World.cpp | 5 | ||||
-rw-r--r-- | src/server/game/World/World.h | 2 |
7 files changed, 56 insertions, 21 deletions
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index 776eb7dbe87..65c49183556 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -79,7 +79,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_DAILY, "SELECT quest, time FROM character_queststatus_daily WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_WEEKLY, "SELECT quest FROM character_queststatus_weekly WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_MONTHLY, "SELECT quest FROM character_queststatus_monthly WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_SEASONAL, "SELECT quest, event FROM character_queststatus_seasonal WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_SEASONAL, "SELECT quest, event, completedTime FROM character_queststatus_seasonal WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_DAILY, "DELETE FROM character_queststatus_daily WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_WEEKLY, "DELETE FROM character_queststatus_weekly WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_MONTHLY, "DELETE FROM character_queststatus_monthly WHERE guid = ?", CONNECTION_ASYNC); @@ -87,11 +87,11 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_INS_CHARACTER_QUESTSTATUS_DAILY, "INSERT INTO character_queststatus_daily (guid, quest, time) VALUES (?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_CHARACTER_QUESTSTATUS_WEEKLY, "INSERT INTO character_queststatus_weekly (guid, quest) VALUES (?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_CHARACTER_QUESTSTATUS_MONTHLY, "INSERT INTO character_queststatus_monthly (guid, quest) VALUES (?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHARACTER_QUESTSTATUS_SEASONAL, "INSERT INTO character_queststatus_seasonal (guid, quest, event) VALUES (?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHARACTER_QUESTSTATUS_SEASONAL, "INSERT INTO character_queststatus_seasonal (guid, quest, event, completedTime) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_DAILY, "DELETE FROM character_queststatus_daily", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_WEEKLY, "DELETE FROM character_queststatus_weekly", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_MONTHLY, "DELETE FROM character_queststatus_monthly", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_SEASONAL_BY_EVENT, "DELETE FROM character_queststatus_seasonal WHERE event = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_SEASONAL_BY_EVENT, "DELETE FROM character_queststatus_seasonal WHERE event = ? AND completedTime < ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_REPUTATION, "SELECT faction, standing, flags FROM character_reputation WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_INVENTORY, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, bag, slot, " diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index e50c46ee1f2..fe8529835b4 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -18546,11 +18546,12 @@ void Player::_LoadSeasonalQuestStatus(PreparedQueryResult result) Field* fields = result->Fetch(); uint32 quest_id = fields[0].GetUInt32(); uint32 event_id = fields[1].GetUInt32(); + uint32 completedTime = fields[2].GetInt64(); Quest const* quest = sObjectMgr->GetQuestTemplate(quest_id); if (!quest) continue; - m_seasonalquests[event_id].insert(quest_id); + m_seasonalquests[event_id][quest_id] = completedTime; TC_LOG_DEBUG("entities.player.loading", "Player::_LoadSeasonalQuestStatus: Loaded seasonal quest cooldown (QuestID: {}) for player '{}' ({})", quest_id, GetName(), GetGUID().ToString()); } @@ -19929,18 +19930,20 @@ void Player::_SaveSeasonalQuestStatus(CharacterDatabaseTransaction trans) if (m_seasonalquests.empty()) return; - for (SeasonalEventQuestMap::const_iterator iter = m_seasonalquests.begin(); iter != m_seasonalquests.end(); ++iter) + for (SeasonalQuestMapByEvent::const_iterator iter = m_seasonalquests.begin(); iter != m_seasonalquests.end(); ++iter) { uint16 eventId = iter->first; - for (SeasonalQuestSet::const_iterator itr = iter->second.begin(); itr != iter->second.end(); ++itr) + for (SeasonalQuestMapByQuest::const_iterator itr = iter->second.begin(); itr != iter->second.end(); ++itr) { - uint32 questId = *itr; + uint32 questId = itr->first; + time_t completedTime = itr->second; stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_QUESTSTATUS_SEASONAL); stmt->setUInt32(0, GetGUID().GetCounter()); stmt->setUInt32(1, questId); stmt->setUInt32(2, eventId); + stmt->setInt64(3, completedTime); trans->Append(stmt); } } @@ -23140,7 +23143,7 @@ void Player::SetSeasonalQuestStatus(uint32 quest_id) if (!quest) return; - m_seasonalquests[quest->GetEventIdForQuest()].insert(quest_id); + m_seasonalquests[quest->GetEventIdForQuest()][quest_id] = GameTime::GetGameTime(); m_SeasonalQuestChanged = true; } @@ -23172,14 +23175,29 @@ void Player::ResetWeeklyQuestStatus() m_WeeklyQuestChanged = false; } -void Player::ResetSeasonalQuestStatus(uint16 event_id) +void Player::ResetSeasonalQuestStatus(uint16 event_id, time_t eventStartTime) { - if (m_seasonalquests.empty() || m_seasonalquests[event_id].empty()) - return; - - m_seasonalquests.erase(event_id); // DB data deleted in caller m_SeasonalQuestChanged = false; + + auto eventItr = m_seasonalquests.find(event_id); + if (eventItr == m_seasonalquests.end()) + return; + + if (eventItr->second.empty()) + return; + + for (auto questItr = eventItr->second.begin(); questItr != eventItr->second.end(); ) + { + if (questItr->second < eventStartTime) + questItr = eventItr->second.erase(questItr); + else + ++questItr; + } + + if (eventItr->second.empty()) + m_seasonalquests.erase(eventItr); + } void Player::ResetMonthlyQuestStatus() diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index efe5e6231dc..bd1ece31ed6 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1299,7 +1299,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void ResetDailyQuestStatus(); void ResetWeeklyQuestStatus(); void ResetMonthlyQuestStatus(); - void ResetSeasonalQuestStatus(uint16 event_id); + void ResetSeasonalQuestStatus(uint16 event_id, time_t eventStartTime); uint16 FindQuestSlot(uint32 quest_id) const; uint32 GetQuestSlotQuestId(uint16 slot) const; @@ -2276,12 +2276,12 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> //We allow only one timed quest active at the same time. Below can then be simple value instead of set. typedef std::set<uint32> QuestSet; - typedef std::set<uint32> SeasonalQuestSet; - typedef std::unordered_map<uint32, SeasonalQuestSet> SeasonalEventQuestMap; + typedef std::unordered_map<uint32, time_t> SeasonalQuestMapByQuest; + typedef std::unordered_map<uint32, SeasonalQuestMapByQuest> SeasonalQuestMapByEvent; QuestSet m_timedquests; QuestSet m_weeklyquests; QuestSet m_monthlyquests; - SeasonalEventQuestMap m_seasonalquests; + SeasonalQuestMapByEvent m_seasonalquests; ObjectGuid m_playerSharingQuest; uint32 m_sharedQuestId; diff --git a/src/server/game/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp index b7c240805ea..53b16101b08 100644 --- a/src/server/game/Events/GameEventMgr.cpp +++ b/src/server/game/Events/GameEventMgr.cpp @@ -1184,7 +1184,7 @@ void GameEventMgr::ApplyNewEvent(uint16 event_id) RunSmartAIScripts(event_id, true); // check for seasonal quest reset. - sWorld->ResetEventSeasonalQuests(event_id); + sWorld->ResetEventSeasonalQuests(event_id, GetLastStartTime(event_id)); } void GameEventMgr::UpdateEventNPCFlags(uint16 event_id) @@ -1818,6 +1818,21 @@ void GameEventMgr::SetHolidayEventTime(GameEventData& event) } } +time_t GameEventMgr::GetLastStartTime(uint16 event_id) const +{ + if (event_id >= mGameEvent.size()) + return 0; + + if (mGameEvent[event_id].state != GAMEEVENT_NORMAL) + return 0; + + SystemTimePoint now = GameTime::GetSystemTime(); + SystemTimePoint eventInitialStart = std::chrono::system_clock::from_time_t(mGameEvent[event_id].start); + Minutes occurence(mGameEvent[event_id].occurence); + SystemTimePoint::duration durationSinceLastStart = (now - eventInitialStart) % occurence; + return std::chrono::system_clock::to_time_t(now - durationSinceLastStart); +} + bool IsHolidayActive(HolidayIds id) { if (id == HOLIDAY_NONE) diff --git a/src/server/game/Events/GameEventMgr.h b/src/server/game/Events/GameEventMgr.h index 4d51ae1ec9b..8417651689d 100644 --- a/src/server/game/Events/GameEventMgr.h +++ b/src/server/game/Events/GameEventMgr.h @@ -148,6 +148,7 @@ class TC_GAME_API GameEventMgr bool hasCreatureActiveEventExcept(ObjectGuid::LowType creature_guid, uint16 event_id); bool hasGameObjectActiveEventExcept(ObjectGuid::LowType go_guid, uint16 event_id); void SetHolidayEventTime(GameEventData& event); + time_t GetLastStartTime(uint16 event_id) const; typedef std::list<ObjectGuid::LowType> GuidList; typedef std::list<uint32> IdList; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 9ec3ed3b51f..f24237bc643 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -3417,17 +3417,18 @@ void World::InitGuildResetTime() sWorld->setWorldState(WS_GUILD_DAILY_RESET_TIME, uint64(m_NextGuildReset)); } -void World::ResetEventSeasonalQuests(uint16 event_id) +void World::ResetEventSeasonalQuests(uint16 event_id, time_t eventStartTime) { TC_LOG_INFO("misc", "Seasonal quests reset for all characters."); CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_SEASONAL_BY_EVENT); stmt->setUInt16(0, event_id); + stmt->setInt64(1, eventStartTime); CharacterDatabase.Execute(stmt); for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) if (itr->second->GetPlayer()) - itr->second->GetPlayer()->ResetSeasonalQuestStatus(event_id); + itr->second->GetPlayer()->ResetSeasonalQuestStatus(event_id, eventStartTime); } void World::ResetRandomBG() diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index e245c419b43..f489a304c0d 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -761,7 +761,7 @@ class TC_GAME_API World uint32 GetCleaningFlags() const { return m_CleaningFlags; } void SetCleaningFlags(uint32 flags) { m_CleaningFlags = flags; } - void ResetEventSeasonalQuests(uint16 event_id); + void ResetEventSeasonalQuests(uint16 event_id, time_t eventStartTime); void ReloadRBAC(); |