diff options
author | Shauren <shauren.trinity@gmail.com> | 2022-07-03 23:44:48 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2022-07-03 23:44:48 +0200 |
commit | 49ad0d2d495a9f817ad2820f8e616f3a6564b480 (patch) | |
tree | 93d6744a952dd4dabba7ef9cfe7f8c3421d2f76a | |
parent | 306022054bec6010a63e80407c8d2f8d672b935b (diff) |
Core/Quests: Reset seasonal quests based on saved completion time and intended holiday start time
-rw-r--r-- | sql/base/characters_database.sql | 4 | ||||
-rw-r--r-- | sql/updates/characters/master/2022_07_03_00_characters.sql | 5 | ||||
-rw-r--r-- | src/server/database/Database/Implementation/CharacterDatabase.cpp | 6 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 39 | ||||
-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 |
9 files changed, 63 insertions, 24 deletions
diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql index 8333e27a4f5..109c9f9e2ee 100644 --- a/sql/base/characters_database.sql +++ b/sql/base/characters_database.sql @@ -1426,6 +1426,7 @@ CREATE TABLE `character_queststatus_seasonal` ( `guid` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'Global Unique Identifier', `quest` int unsigned NOT NULL DEFAULT '0' COMMENT 'Quest Identifier', `event` int unsigned NOT NULL DEFAULT '0' COMMENT 'Event Identifier', + `completedTime` bigint NOT NULL DEFAULT '0', PRIMARY KEY (`guid`,`quest`), KEY `idx_guid` (`guid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Player System'; @@ -3670,7 +3671,8 @@ INSERT INTO `updates` VALUES ('2022_02_28_00_characters_2020_09_27_00_characters.sql','2292A1ED0E7F46DEC41384F75FA6D9461464EEB8','ARCHIVED','2022-02-28 12:43:58',0), ('2022_03_06_00_characters.sql','474AAF9D03E6A56017899C968DC9875368301934','ARCHIVED','2022-03-06 15:12:24',0), ('2022_03_11_00_characters_2021_07_18_00_characters.sql','0BA579ED21F4E75AC2B4797421B5029568B3F6E2','RELEASED','2022-03-11 18:56:07',0), -('2022_06_01_00_characters.sql','582AC6E256F8365F83AB70BA165CCC8B218E19FF','RELEASED','2022-06-01 21:16:56',0); +('2022_06_01_00_characters.sql','582AC6E256F8365F83AB70BA165CCC8B218E19FF','RELEASED','2022-06-01 21:16:56',0), +('2022_07_03_00_characters.sql','D3F04078C0846BCF7C8330AC20C39B8C3AEE7002','RELEASED','2022-07-03 23:37:24',0); /*!40000 ALTER TABLE `updates` ENABLE KEYS */; UNLOCK TABLES; diff --git a/sql/updates/characters/master/2022_07_03_00_characters.sql b/sql/updates/characters/master/2022_07_03_00_characters.sql new file mode 100644 index 00000000000..11ed0f7e42c --- /dev/null +++ b/sql/updates/characters/master/2022_07_03_00_characters.sql @@ -0,0 +1,5 @@ +ALTER TABLE `character_queststatus_seasonal` ADD `completedTime` bigint NOT NULL DEFAULT '0' AFTER `event`; + +UPDATE `character_queststatus_seasonal` SET `completedTime` = UNIX_TIMESTAMP(); + +DELETE FROM `worldstates` WHERE `entry` BETWEEN 1 AND 85; diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index dc39e147e52..26d6648d15e 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -104,7 +104,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); @@ -112,11 +112,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 " SelectItemInstanceContent ", bag, slot FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid WHERE ci.guid = ? ORDER BY (ii.flags & 0x80000) ASC, bag ASC, slot ASC", CONNECTION_ASYNC); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index e0420958d71..00750ba6501 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -19635,11 +19635,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; if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(quest_id)) SetQuestCompletedBit(questBit, true); @@ -21300,18 +21301,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->setUInt64(0, GetGUID().GetCounter()); stmt->setUInt32(1, questId); stmt->setUInt32(2, eventId); + stmt->setInt64(3, completedTime); trans->Append(stmt); } } @@ -25043,7 +25046,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; } @@ -25089,8 +25092,11 @@ void Player::ResetWeeklyQuestStatus() m_WeeklyQuestChanged = false; } -void Player::ResetSeasonalQuestStatus(uint16 event_id) +void Player::ResetSeasonalQuestStatus(uint16 event_id, time_t eventStartTime) { + // DB data deleted in caller + m_SeasonalQuestChanged = false; + auto eventItr = m_seasonalquests.find(event_id); if (eventItr == m_seasonalquests.end()) return; @@ -25098,13 +25104,22 @@ void Player::ResetSeasonalQuestStatus(uint16 event_id) if (eventItr->second.empty()) return; - for (uint32 questId : eventItr->second) - if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(questId)) - SetQuestCompletedBit(questBit, false); + for (auto questItr = eventItr->second.begin(); questItr != eventItr->second.end(); ) + { + if (questItr->second < eventStartTime) + { + if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(questItr->first)) + SetQuestCompletedBit(questBit, false); + + questItr = eventItr->second.erase(questItr); + } + else + ++questItr; + } + + if (eventItr->second.empty()) + m_seasonalquests.erase(eventItr); - m_seasonalquests.erase(eventItr); - // DB data deleted in caller - m_SeasonalQuestChanged = false; } void Player::ResetMonthlyQuestStatus() diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index ae34c91f697..efa7e7ef760 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1612,7 +1612,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void DailyReset(); 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; @@ -2866,12 +2866,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 78c6741a8e8..5dc3630af91 100644 --- a/src/server/game/Events/GameEventMgr.cpp +++ b/src/server/game/Events/GameEventMgr.cpp @@ -1147,7 +1147,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) @@ -1805,6 +1805,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 ba13beb0b59..b0654119567 100644 --- a/src/server/game/Events/GameEventMgr.h +++ b/src/server/game/Events/GameEventMgr.h @@ -139,6 +139,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 17247bde9d7..0639b31e678 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -3716,17 +3716,18 @@ void World::ResetCurrencyWeekCap() sWorld->setWorldState(WS_CURRENCY_RESET_TIME, uint32(m_NextCurrencyReset)); } -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 70634f51a42..214e9cbd6c0 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -794,7 +794,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(); |