Core/Quests: Reset seasonal quests based on saved completion time and intended holiday start time

This commit is contained in:
Shauren authored and Ovahlord committed 2022-12-24 23:56:06 +01:00
1 parent e7f8a0e086
commit 3ae02de71b
9 files changed
+63 -22

No files matched your search

+2
View File
@@ -1239,6 +1239,7 @@ CREATE TABLE `character_queststatus_seasonal` (
`guid` int 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';
@@ -3058,6 +3059,7 @@ INSERT INTO `updates` VALUES
('2022_01_09_00_characters.sql','1420602F3A6F5AAE1CB59045C47E33A3CE8809A4','ARCHIVED','2022-01-09 00:12:22',0),
('2022_09_01_00_characters.sql','E3C0DA9995BA71ED5A267294470CD03DC51862DD','RELEASED','2022-09-01 14:51:33',0),
('2022_09_03_00_characters.sql','50429D68E6EBD1149CDA14A9EA642BC06A1FAE3D','RELEASED','2022-09-03 11:03:06',0),
('2022_12_24_00_characters.sql','D3F04078C0846BCF7C8330AC20C39B8C3AEE7002','RELEASED','2022-12-24 23:52:52',0),
('custom_2017_12_21_00_characters.sql','2D5B3830D47E4BC717EC468E18E477A32B9A21BF','ARCHIVED','2019-11-06 00:17:44',0),
('custom_2018_01_07_00_characters.sql','7437B6243B3CB6FA08F6A37BB39E38930B0DCFD3','ARCHIVED','2019-11-06 00:17:44',0),
('custom_2018_03_18_00_characters.sql','8D1E81A7272F643687C67443C270D17255A9AA84','ARCHIVED','2019-11-06 00:17:44',0),
@@ -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;
@@ -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_REWARDSTATUS_LFG, "SELECT dungeonId, rewardCount, dailyReset FROM character_rewardstatus_lfg WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHARACTER_REWARDSTATUS_LFG, "DELETE FROM character_rewardstatus_lfg WHERE guid = ?", CONNECTION_ASYNC);
+27 -10
View File
@@ -18178,11 +18178,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: %u) for player '%s' (%s)",
quest_id, GetName().c_str(), GetGUID().ToString().c_str());
}
@@ -19717,18 +19718,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);
}
}
@@ -23310,7 +23313,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;
}
@@ -23353,14 +23356,28 @@ void Player::ResetWeeklyQuestStatus()
}
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()
+4 -4
View File
@@ -1376,7 +1376,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);
void ResetWeeklyLFGRewardStatus();
void ResetDailyLFGRewardStatus();
@@ -2405,8 +2405,8 @@ 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;
struct LFGRewardInfo
{
@@ -2422,7 +2422,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
QuestSet m_timedquests;
QuestSet m_weeklyquests;
QuestSet m_monthlyquests;
SeasonalEventQuestMap m_seasonalquests;
SeasonalQuestMapByEvent m_seasonalquests;
LFGRewardStatusMap m_lfgrewardstatus;
ObjectGuid m_playerSharingQuest;
+16 -1
View File
@@ -1175,7 +1175,7 @@ void GameEventMgr::ApplyNewEvent(uint16 event_id)
// update bg holiday
UpdateBattlegroundSettings();
// check for seasonal quest reset.
sWorld->ResetEventSeasonalQuests(event_id);
sWorld->ResetEventSeasonalQuests(event_id, GetLastStartTime(event_id));
}
void GameEventMgr::UpdateEventNPCFlags(uint16 event_id)
@@ -1815,6 +1815,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;
std::chrono::system_clock::time_point now = GameTime::GetGameTimeSystemPoint();
std::chrono::system_clock::time_point eventInitialStart = std::chrono::system_clock::from_time_t(mGameEvent[event_id].start);
Minutes occurence(mGameEvent[event_id].occurence);
std::chrono::system_clock::time_point::duration durationSinceLastStart = (now - eventInitialStart) % occurence;
return std::chrono::system_clock::to_time_t(now - durationSinceLastStart);
}
bool IsHolidayActive(HolidayIds id)
{
if (id == HOLIDAY_NONE)
+1
View File
@@ -140,6 +140,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;
+3 -2
View File
@@ -3513,17 +3513,18 @@ void World::SetPlayerSecurityLimit(AccountTypes _sec)
KickAllLess(m_allowedSecurityLevel);
}
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()
+2 -2
View File
@@ -787,8 +787,8 @@ class TC_GAME_API World
void UpdateAreaDependentAuras();
uint32 GetCleaningFlags() const { return m_CleaningFlags; }
void SetCleaningFlags(uint32 flags) { m_CleaningFlags = flags; }
void ResetEventSeasonalQuests(uint16 event_id);
void SetCleaningFlags(uint32 flags) { m_CleaningFlags = flags; }
void ResetEventSeasonalQuests(uint16 event_id, time_t eventStartTime);
void ReloadRBAC();