Skip to content

Commit cbabaa0

Browse files
ShaurenErgar
authored andcommitted
Core/Quests: Reset seasonal quests based on saved completion time and intended holiday start time
(cherry picked from commit 49ad0d2)
1 parent 97b16e2 commit cbabaa0

File tree

9 files changed

+64
-22
lines changed

9 files changed

+64
-22
lines changed

sql/base/characters_database.sql

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1088,6 +1088,7 @@ CREATE TABLE `character_queststatus_seasonal` (
10881088
`guid` int unsigned NOT NULL DEFAULT '0' COMMENT 'Global Unique Identifier',
10891089
`quest` int unsigned NOT NULL DEFAULT '0' COMMENT 'Quest Identifier',
10901090
`event` int unsigned NOT NULL DEFAULT '0' COMMENT 'Event Identifier',
1091+
`completedTime` bigint NOT NULL DEFAULT '0',
10911092
PRIMARY KEY (`guid`,`quest`),
10921093
KEY `idx_guid` (`guid`)
10931094
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Player System';
@@ -2688,7 +2689,8 @@ INSERT INTO `updates` VALUES
26882689
('2024_04_10_00_characters.sql','E0D6E19ACE6759332402FA27C23B0F7745C49742','ARCHIVED','2024-04-10 16:07:02',0),
26892690
('2024_08_17_00_characters.sql','08705FBCB8504E8B1009FDAF955F56D734FAD782','ARCHIVED','2024-08-17 22:26:12',0),
26902691
('2024_10_03_00_characters.sql','408249A6992999A36EB94089D184972E8E0767A3','ARCHIVED','2024-10-03 11:10:18',0),
2691-
('2024_11_22_00_characters.sql','9EA2A4F88036D1D5F47EE8A6B634D52D0014986E','ARCHIVED','2024-11-22 23:18:14',0);
2692+
('2024_11_22_00_characters.sql','9EA2A4F88036D1D5F47EE8A6B634D52D0014986E','ARCHIVED','2024-11-22 23:18:14',0),
2693+
('2025_07_20_00_characters_2022_07_03_00_characters.sql','D3F04078C0846BCF7C8330AC20C39B8C3AEE7002','RELEASED','2022-07-03 23:37:24',0);
26922694
/*!40000 ALTER TABLE `updates` ENABLE KEYS */;
26932695
UNLOCK TABLES;
26942696

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
ALTER TABLE `character_queststatus_seasonal` ADD `completedTime` bigint NOT NULL DEFAULT '0' AFTER `event`;
2+
3+
UPDATE `character_queststatus_seasonal` SET `completedTime` = UNIX_TIMESTAMP();
4+
5+
DELETE FROM `worldstates` WHERE `entry` BETWEEN 1 AND 85;

src/server/database/Database/Implementation/CharacterDatabase.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,19 +79,19 @@ void CharacterDatabaseConnection::DoPrepareStatements()
7979
PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_DAILY, "SELECT quest, time FROM character_queststatus_daily WHERE guid = ?", CONNECTION_ASYNC);
8080
PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_WEEKLY, "SELECT quest FROM character_queststatus_weekly WHERE guid = ?", CONNECTION_ASYNC);
8181
PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_MONTHLY, "SELECT quest FROM character_queststatus_monthly WHERE guid = ?", CONNECTION_ASYNC);
82-
PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_SEASONAL, "SELECT quest, event FROM character_queststatus_seasonal WHERE guid = ?", CONNECTION_ASYNC);
82+
PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_SEASONAL, "SELECT quest, event, completedTime FROM character_queststatus_seasonal WHERE guid = ?", CONNECTION_ASYNC);
8383
PrepareStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_DAILY, "DELETE FROM character_queststatus_daily WHERE guid = ?", CONNECTION_ASYNC);
8484
PrepareStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_WEEKLY, "DELETE FROM character_queststatus_weekly WHERE guid = ?", CONNECTION_ASYNC);
8585
PrepareStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_MONTHLY, "DELETE FROM character_queststatus_monthly WHERE guid = ?", CONNECTION_ASYNC);
8686
PrepareStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_SEASONAL, "DELETE FROM character_queststatus_seasonal WHERE guid = ?", CONNECTION_ASYNC);
8787
PrepareStatement(CHAR_INS_CHARACTER_QUESTSTATUS_DAILY, "INSERT INTO character_queststatus_daily (guid, quest, time) VALUES (?, ?, ?)", CONNECTION_ASYNC);
8888
PrepareStatement(CHAR_INS_CHARACTER_QUESTSTATUS_WEEKLY, "INSERT INTO character_queststatus_weekly (guid, quest) VALUES (?, ?)", CONNECTION_ASYNC);
8989
PrepareStatement(CHAR_INS_CHARACTER_QUESTSTATUS_MONTHLY, "INSERT INTO character_queststatus_monthly (guid, quest) VALUES (?, ?)", CONNECTION_ASYNC);
90-
PrepareStatement(CHAR_INS_CHARACTER_QUESTSTATUS_SEASONAL, "INSERT INTO character_queststatus_seasonal (guid, quest, event) VALUES (?, ?, ?)", CONNECTION_ASYNC);
90+
PrepareStatement(CHAR_INS_CHARACTER_QUESTSTATUS_SEASONAL, "INSERT INTO character_queststatus_seasonal (guid, quest, event, completedTime) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
9191
PrepareStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_DAILY, "DELETE FROM character_queststatus_daily", CONNECTION_ASYNC);
9292
PrepareStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_WEEKLY, "DELETE FROM character_queststatus_weekly", CONNECTION_ASYNC);
9393
PrepareStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_MONTHLY, "DELETE FROM character_queststatus_monthly", CONNECTION_ASYNC);
94-
PrepareStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_SEASONAL_BY_EVENT, "DELETE FROM character_queststatus_seasonal WHERE event = ?", CONNECTION_ASYNC);
94+
PrepareStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_SEASONAL_BY_EVENT, "DELETE FROM character_queststatus_seasonal WHERE event = ? AND completedTime < ?", CONNECTION_ASYNC);
9595

9696
PrepareStatement(CHAR_SEL_CHARACTER_REPUTATION, "SELECT faction, standing, flags FROM character_reputation WHERE guid = ?", CONNECTION_ASYNC);
9797
PrepareStatement(CHAR_SEL_CHARACTER_INVENTORY, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, bag, slot, "

src/server/game/Entities/Player/Player.cpp

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18546,11 +18546,12 @@ void Player::_LoadSeasonalQuestStatus(PreparedQueryResult result)
1854618546
Field* fields = result->Fetch();
1854718547
uint32 quest_id = fields[0].GetUInt32();
1854818548
uint32 event_id = fields[1].GetUInt32();
18549+
uint32 completedTime = fields[2].GetInt64();
1854918550
Quest const* quest = sObjectMgr->GetQuestTemplate(quest_id);
1855018551
if (!quest)
1855118552
continue;
1855218553

18553-
m_seasonalquests[event_id].insert(quest_id);
18554+
m_seasonalquests[event_id][quest_id] = completedTime;
1855418555
TC_LOG_DEBUG("entities.player.loading", "Player::_LoadSeasonalQuestStatus: Loaded seasonal quest cooldown (QuestID: {}) for player '{}' ({})",
1855518556
quest_id, GetName(), GetGUID().ToString());
1855618557
}
@@ -19929,18 +19930,20 @@ void Player::_SaveSeasonalQuestStatus(CharacterDatabaseTransaction trans)
1992919930
if (m_seasonalquests.empty())
1993019931
return;
1993119932

19932-
for (SeasonalEventQuestMap::const_iterator iter = m_seasonalquests.begin(); iter != m_seasonalquests.end(); ++iter)
19933+
for (SeasonalQuestMapByEvent::const_iterator iter = m_seasonalquests.begin(); iter != m_seasonalquests.end(); ++iter)
1993319934
{
1993419935
uint16 eventId = iter->first;
1993519936

19936-
for (SeasonalQuestSet::const_iterator itr = iter->second.begin(); itr != iter->second.end(); ++itr)
19937+
for (SeasonalQuestMapByQuest::const_iterator itr = iter->second.begin(); itr != iter->second.end(); ++itr)
1993719938
{
19938-
uint32 questId = *itr;
19939+
uint32 questId = itr->first;
19940+
time_t completedTime = itr->second;
1993919941

1994019942
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_QUESTSTATUS_SEASONAL);
1994119943
stmt->setUInt32(0, GetGUID().GetCounter());
1994219944
stmt->setUInt32(1, questId);
1994319945
stmt->setUInt32(2, eventId);
19946+
stmt->setInt64(3, completedTime);
1994419947
trans->Append(stmt);
1994519948
}
1994619949
}
@@ -23140,7 +23143,7 @@ void Player::SetSeasonalQuestStatus(uint32 quest_id)
2314023143
if (!quest)
2314123144
return;
2314223145

23143-
m_seasonalquests[quest->GetEventIdForQuest()].insert(quest_id);
23146+
m_seasonalquests[quest->GetEventIdForQuest()][quest_id] = GameTime::GetGameTime();
2314423147
m_SeasonalQuestChanged = true;
2314523148
}
2314623149

@@ -23172,14 +23175,29 @@ void Player::ResetWeeklyQuestStatus()
2317223175
m_WeeklyQuestChanged = false;
2317323176
}
2317423177

23175-
void Player::ResetSeasonalQuestStatus(uint16 event_id)
23178+
void Player::ResetSeasonalQuestStatus(uint16 event_id, time_t eventStartTime)
2317623179
{
23177-
if (m_seasonalquests.empty() || m_seasonalquests[event_id].empty())
23178-
return;
23179-
23180-
m_seasonalquests.erase(event_id);
2318123180
// DB data deleted in caller
2318223181
m_SeasonalQuestChanged = false;
23182+
23183+
auto eventItr = m_seasonalquests.find(event_id);
23184+
if (eventItr == m_seasonalquests.end())
23185+
return;
23186+
23187+
if (eventItr->second.empty())
23188+
return;
23189+
23190+
for (auto questItr = eventItr->second.begin(); questItr != eventItr->second.end(); )
23191+
{
23192+
if (questItr->second < eventStartTime)
23193+
questItr = eventItr->second.erase(questItr);
23194+
else
23195+
++questItr;
23196+
}
23197+
23198+
if (eventItr->second.empty())
23199+
m_seasonalquests.erase(eventItr);
23200+
2318323201
}
2318423202

2318523203
void Player::ResetMonthlyQuestStatus()

src/server/game/Entities/Player/Player.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,7 +1299,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
12991299
void ResetDailyQuestStatus();
13001300
void ResetWeeklyQuestStatus();
13011301
void ResetMonthlyQuestStatus();
1302-
void ResetSeasonalQuestStatus(uint16 event_id);
1302+
void ResetSeasonalQuestStatus(uint16 event_id, time_t eventStartTime);
13031303

13041304
uint16 FindQuestSlot(uint32 quest_id) const;
13051305
uint32 GetQuestSlotQuestId(uint16 slot) const;
@@ -2276,12 +2276,12 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
22762276

22772277
//We allow only one timed quest active at the same time. Below can then be simple value instead of set.
22782278
typedef std::set<uint32> QuestSet;
2279-
typedef std::set<uint32> SeasonalQuestSet;
2280-
typedef std::unordered_map<uint32, SeasonalQuestSet> SeasonalEventQuestMap;
2279+
typedef std::unordered_map<uint32, time_t> SeasonalQuestMapByQuest;
2280+
typedef std::unordered_map<uint32, SeasonalQuestMapByQuest> SeasonalQuestMapByEvent;
22812281
QuestSet m_timedquests;
22822282
QuestSet m_weeklyquests;
22832283
QuestSet m_monthlyquests;
2284-
SeasonalEventQuestMap m_seasonalquests;
2284+
SeasonalQuestMapByEvent m_seasonalquests;
22852285

22862286
ObjectGuid m_playerSharingQuest;
22872287
uint32 m_sharedQuestId;

src/server/game/Events/GameEventMgr.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1184,7 +1184,7 @@ void GameEventMgr::ApplyNewEvent(uint16 event_id)
11841184
RunSmartAIScripts(event_id, true);
11851185

11861186
// check for seasonal quest reset.
1187-
sWorld->ResetEventSeasonalQuests(event_id);
1187+
sWorld->ResetEventSeasonalQuests(event_id, GetLastStartTime(event_id));
11881188
}
11891189

11901190
void GameEventMgr::UpdateEventNPCFlags(uint16 event_id)
@@ -1818,6 +1818,21 @@ void GameEventMgr::SetHolidayEventTime(GameEventData& event)
18181818
}
18191819
}
18201820

1821+
time_t GameEventMgr::GetLastStartTime(uint16 event_id) const
1822+
{
1823+
if (event_id >= mGameEvent.size())
1824+
return 0;
1825+
1826+
if (mGameEvent[event_id].state != GAMEEVENT_NORMAL)
1827+
return 0;
1828+
1829+
SystemTimePoint now = GameTime::GetSystemTime();
1830+
SystemTimePoint eventInitialStart = std::chrono::system_clock::from_time_t(mGameEvent[event_id].start);
1831+
Minutes occurence(mGameEvent[event_id].occurence);
1832+
SystemTimePoint::duration durationSinceLastStart = (now - eventInitialStart) % occurence;
1833+
return std::chrono::system_clock::to_time_t(now - durationSinceLastStart);
1834+
}
1835+
18211836
bool IsHolidayActive(HolidayIds id)
18221837
{
18231838
if (id == HOLIDAY_NONE)

src/server/game/Events/GameEventMgr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ class TC_GAME_API GameEventMgr
148148
bool hasCreatureActiveEventExcept(ObjectGuid::LowType creature_guid, uint16 event_id);
149149
bool hasGameObjectActiveEventExcept(ObjectGuid::LowType go_guid, uint16 event_id);
150150
void SetHolidayEventTime(GameEventData& event);
151+
time_t GetLastStartTime(uint16 event_id) const;
151152

152153
typedef std::list<ObjectGuid::LowType> GuidList;
153154
typedef std::list<uint32> IdList;

src/server/game/World/World.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3417,17 +3417,18 @@ void World::InitGuildResetTime()
34173417
sWorld->setWorldState(WS_GUILD_DAILY_RESET_TIME, uint64(m_NextGuildReset));
34183418
}
34193419

3420-
void World::ResetEventSeasonalQuests(uint16 event_id)
3420+
void World::ResetEventSeasonalQuests(uint16 event_id, time_t eventStartTime)
34213421
{
34223422
TC_LOG_INFO("misc", "Seasonal quests reset for all characters.");
34233423

34243424
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_SEASONAL_BY_EVENT);
34253425
stmt->setUInt16(0, event_id);
3426+
stmt->setInt64(1, eventStartTime);
34263427
CharacterDatabase.Execute(stmt);
34273428

34283429
for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
34293430
if (itr->second->GetPlayer())
3430-
itr->second->GetPlayer()->ResetSeasonalQuestStatus(event_id);
3431+
itr->second->GetPlayer()->ResetSeasonalQuestStatus(event_id, eventStartTime);
34313432
}
34323433

34333434
void World::ResetRandomBG()

src/server/game/World/World.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,7 @@ class TC_GAME_API World
761761

762762
uint32 GetCleaningFlags() const { return m_CleaningFlags; }
763763
void SetCleaningFlags(uint32 flags) { m_CleaningFlags = flags; }
764-
void ResetEventSeasonalQuests(uint16 event_id);
764+
void ResetEventSeasonalQuests(uint16 event_id, time_t eventStartTime);
765765

766766
void ReloadRBAC();
767767

0 commit comments

Comments
 (0)