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

Port From (https://github.com/TrinityCore/TrinityCore/commit/49ad0d2d495a9f817ad2820f8e616f3a6564b480)
This commit is contained in:
hondacrx
2022-07-04 01:15:52 -04:00
parent 3a402854aa
commit c7123ad860
8 changed files with 69 additions and 27 deletions
@@ -101,7 +101,7 @@ namespace Framework.Database
PrepareStatement(CharStatements.SEL_CHARACTER_QUESTSTATUS_DAILY, "SELECT quest, time FROM character_queststatus_daily WHERE guid = ?"); PrepareStatement(CharStatements.SEL_CHARACTER_QUESTSTATUS_DAILY, "SELECT quest, time FROM character_queststatus_daily WHERE guid = ?");
PrepareStatement(CharStatements.SEL_CHARACTER_QUESTSTATUS_WEEKLY, "SELECT quest FROM character_queststatus_weekly WHERE guid = ?"); PrepareStatement(CharStatements.SEL_CHARACTER_QUESTSTATUS_WEEKLY, "SELECT quest FROM character_queststatus_weekly WHERE guid = ?");
PrepareStatement(CharStatements.SEL_CHARACTER_QUESTSTATUS_MONTHLY, "SELECT quest FROM character_queststatus_monthly WHERE guid = ?"); PrepareStatement(CharStatements.SEL_CHARACTER_QUESTSTATUS_MONTHLY, "SELECT quest FROM character_queststatus_monthly WHERE guid = ?");
PrepareStatement(CharStatements.SEL_CHARACTER_QUESTSTATUS_SEASONAL, "SELECT quest, event FROM character_queststatus_seasonal WHERE guid = ?"); PrepareStatement(CharStatements.SEL_CHARACTER_QUESTSTATUS_SEASONAL, "SELECT quest, event, completedTime FROM character_queststatus_seasonal WHERE guid = ?");
PrepareStatement(CharStatements.DEL_CHARACTER_QUESTSTATUS_DAILY, "DELETE FROM character_queststatus_daily WHERE guid = ?"); PrepareStatement(CharStatements.DEL_CHARACTER_QUESTSTATUS_DAILY, "DELETE FROM character_queststatus_daily WHERE guid = ?");
PrepareStatement(CharStatements.DEL_CHARACTER_QUESTSTATUS_WEEKLY, "DELETE FROM character_queststatus_weekly WHERE guid = ?"); PrepareStatement(CharStatements.DEL_CHARACTER_QUESTSTATUS_WEEKLY, "DELETE FROM character_queststatus_weekly WHERE guid = ?");
PrepareStatement(CharStatements.DEL_CHARACTER_QUESTSTATUS_MONTHLY, "DELETE FROM character_queststatus_monthly WHERE guid = ?"); PrepareStatement(CharStatements.DEL_CHARACTER_QUESTSTATUS_MONTHLY, "DELETE FROM character_queststatus_monthly WHERE guid = ?");
@@ -109,11 +109,11 @@ namespace Framework.Database
PrepareStatement(CharStatements.INS_CHARACTER_QUESTSTATUS_DAILY, "INSERT INTO character_queststatus_daily (guid, quest, time) VALUES (?, ?, ?)"); PrepareStatement(CharStatements.INS_CHARACTER_QUESTSTATUS_DAILY, "INSERT INTO character_queststatus_daily (guid, quest, time) VALUES (?, ?, ?)");
PrepareStatement(CharStatements.INS_CHARACTER_QUESTSTATUS_WEEKLY, "INSERT INTO character_queststatus_weekly (guid, quest) VALUES (?, ?)"); PrepareStatement(CharStatements.INS_CHARACTER_QUESTSTATUS_WEEKLY, "INSERT INTO character_queststatus_weekly (guid, quest) VALUES (?, ?)");
PrepareStatement(CharStatements.INS_CHARACTER_QUESTSTATUS_MONTHLY, "INSERT INTO character_queststatus_monthly (guid, quest) VALUES (?, ?)"); PrepareStatement(CharStatements.INS_CHARACTER_QUESTSTATUS_MONTHLY, "INSERT INTO character_queststatus_monthly (guid, quest) VALUES (?, ?)");
PrepareStatement(CharStatements.INS_CHARACTER_QUESTSTATUS_SEASONAL, "INSERT INTO character_queststatus_seasonal (guid, quest, event) VALUES (?, ?, ?)"); PrepareStatement(CharStatements.INS_CHARACTER_QUESTSTATUS_SEASONAL, "INSERT INTO character_queststatus_seasonal (guid, quest, event, completedTime) VALUES (?, ?, ?, ?)");
PrepareStatement(CharStatements.DEL_RESET_CHARACTER_QUESTSTATUS_DAILY, "DELETE FROM character_queststatus_daily"); PrepareStatement(CharStatements.DEL_RESET_CHARACTER_QUESTSTATUS_DAILY, "DELETE FROM character_queststatus_daily");
PrepareStatement(CharStatements.DEL_RESET_CHARACTER_QUESTSTATUS_WEEKLY, "DELETE FROM character_queststatus_weekly"); PrepareStatement(CharStatements.DEL_RESET_CHARACTER_QUESTSTATUS_WEEKLY, "DELETE FROM character_queststatus_weekly");
PrepareStatement(CharStatements.DEL_RESET_CHARACTER_QUESTSTATUS_MONTHLY, "DELETE FROM character_queststatus_monthly"); PrepareStatement(CharStatements.DEL_RESET_CHARACTER_QUESTSTATUS_MONTHLY, "DELETE FROM character_queststatus_monthly");
PrepareStatement(CharStatements.DEL_RESET_CHARACTER_QUESTSTATUS_SEASONAL_BY_EVENT, "DELETE FROM character_queststatus_seasonal WHERE event = ?"); PrepareStatement(CharStatements.DEL_RESET_CHARACTER_QUESTSTATUS_SEASONAL_BY_EVENT, "DELETE FROM character_queststatus_seasonal WHERE event = ? AND completedTime < ?");
PrepareStatement(CharStatements.SEL_CHARACTER_REPUTATION, "SELECT faction, standing, flags FROM character_reputation WHERE guid = ?"); PrepareStatement(CharStatements.SEL_CHARACTER_REPUTATION, "SELECT faction, standing, flags FROM character_reputation WHERE guid = ?");
PrepareStatement(CharStatements.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"); PrepareStatement(CharStatements.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");
+13 -4
View File
@@ -931,11 +931,16 @@ namespace Game.Entities
{ {
uint quest_id = result.Read<uint>(0); uint quest_id = result.Read<uint>(0);
uint event_id = result.Read<uint>(1); uint event_id = result.Read<uint>(1);
long completedTime = result.Read<long>(2);
Quest quest = Global.ObjectMgr.GetQuestTemplate(quest_id); Quest quest = Global.ObjectMgr.GetQuestTemplate(quest_id);
if (quest == null) if (quest == null)
continue; continue;
m_seasonalquests.Add(event_id, quest_id); if (!m_seasonalquests.ContainsKey(event_id))
m_seasonalquests[event_id] = new();
m_seasonalquests[event_id][quest_id] = completedTime;
uint questBit = Global.DB2Mgr.GetQuestUniqueBitFlag(quest_id); uint questBit = Global.DB2Mgr.GetQuestUniqueBitFlag(quest_id);
if (questBit != 0) if (questBit != 0)
SetQuestCompletedBit(questBit, true); SetQuestCompletedBit(questBit, true);
@@ -2128,15 +2133,19 @@ namespace Game.Entities
if (m_seasonalquests.Empty()) if (m_seasonalquests.Empty())
return; return;
foreach (var iter in m_seasonalquests) foreach (var (eventId, dictionary) in m_seasonalquests)
{
foreach (var (questId, completedTime) in dictionary)
{ {
stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_CHARACTER_QUESTSTATUS_SEASONAL); stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_CHARACTER_QUESTSTATUS_SEASONAL);
stmt.AddValue(0, GetGUID().GetCounter()); stmt.AddValue(0, GetGUID().GetCounter());
stmt.AddValue(1, iter.Value); stmt.AddValue(1, questId);
stmt.AddValue(2, iter.Key); stmt.AddValue(2, eventId);
stmt.AddValue(3, completedTime);
trans.Append(stmt); trans.Append(stmt);
} }
} }
}
void _SaveMonthlyQuestStatus(SQLTransaction trans) void _SaveMonthlyQuestStatus(SQLTransaction trans)
{ {
if (!m_MonthlyQuestChanged || m_monthlyquests.Empty()) if (!m_MonthlyQuestChanged || m_monthlyquests.Empty())
+1 -1
View File
@@ -164,7 +164,7 @@ namespace Game.Entities
List<uint> m_timedquests = new(); List<uint> m_timedquests = new();
List<uint> m_weeklyquests = new(); List<uint> m_weeklyquests = new();
List<uint> m_monthlyquests = new(); List<uint> m_monthlyquests = new();
MultiMap<uint, uint> m_seasonalquests = new(); Dictionary<uint, Dictionary<uint, long>> m_seasonalquests = new();
Dictionary<uint, QuestStatusData> m_QuestStatus = new(); Dictionary<uint, QuestStatusData> m_QuestStatus = new();
MultiMap<(QuestObjectiveType Type, int ObjectID), QuestObjectiveStatusData> m_questObjectiveStatus = new(); MultiMap<(QuestObjectiveType Type, int ObjectID), QuestObjectiveStatusData> m_questObjectiveStatus = new();
Dictionary<uint, QuestSaveType> m_QuestStatusSave = new(); Dictionary<uint, QuestSaveType> m_QuestStatusSave = new();
+18 -7
View File
@@ -28,6 +28,7 @@ using Game.Networking.Packets;
using Game.Spells; using Game.Spells;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
namespace Game.Entities namespace Game.Entities
{ {
@@ -200,22 +201,29 @@ namespace Game.Entities
} }
public void ResetSeasonalQuestStatus(ushort event_id) public void ResetSeasonalQuestStatus(ushort event_id, long eventStartTime)
{ {
// DB data deleted in caller
m_SeasonalQuestChanged = false;
var eventList = m_seasonalquests.LookupByKey(event_id); var eventList = m_seasonalquests.LookupByKey(event_id);
if (eventList.Empty()) if (eventList.Empty())
return; return;
foreach (uint questId in eventList) foreach (var (questId, completedTime) in eventList.ToList())
{
if (completedTime < eventStartTime)
{ {
uint questBit = Global.DB2Mgr.GetQuestUniqueBitFlag(questId); uint questBit = Global.DB2Mgr.GetQuestUniqueBitFlag(questId);
if (questBit != 0) if (questBit != 0)
SetQuestCompletedBit(questBit, false); SetQuestCompletedBit(questBit, false);
eventList.Remove(questId);
}
} }
if (eventList.Empty())
m_seasonalquests.Remove(event_id); m_seasonalquests.Remove(event_id);
// DB data deleted in caller
m_SeasonalQuestChanged = false;
} }
public void ResetMonthlyQuestStatus() public void ResetMonthlyQuestStatus()
@@ -1673,7 +1681,7 @@ namespace Game.Entities
return true; return true;
// if not found in cooldown list // if not found in cooldown list
return !list.Contains(qInfo.Id); return !list.ContainsKey(qInfo.Id);
} }
public bool SatisfyQuestExpansion(Quest qInfo, bool msg) public bool SatisfyQuestExpansion(Quest qInfo, bool msg)
@@ -1864,7 +1872,7 @@ namespace Game.Entities
ushort eventId = qInfo.GetEventIdForQuest(); ushort eventId = qInfo.GetEventIdForQuest();
if (m_seasonalquests.ContainsKey(eventId)) if (m_seasonalquests.ContainsKey(eventId))
{ {
m_seasonalquests.Remove(eventId, questId); m_seasonalquests[eventId].Remove(questId);
m_SeasonalQuestChanged = true; m_SeasonalQuestChanged = true;
} }
} }
@@ -3041,7 +3049,10 @@ namespace Game.Entities
if (quest == null) if (quest == null)
return; return;
m_seasonalquests.Add(quest.GetEventIdForQuest(), quest_id); if (!m_seasonalquests.ContainsKey(quest.GetEventIdForQuest()))
m_seasonalquests[quest.GetEventIdForQuest()] = new();
m_seasonalquests[quest.GetEventIdForQuest()][quest_id] = GameTime.GetGameTime();
m_SeasonalQuestChanged = true; m_SeasonalQuestChanged = true;
} }
+16 -1
View File
@@ -1100,7 +1100,7 @@ namespace Game
RunSmartAIScripts(event_id, true); RunSmartAIScripts(event_id, true);
// check for seasonal quest reset. // check for seasonal quest reset.
Global.WorldMgr.ResetEventSeasonalQuests(event_id); Global.WorldMgr.ResetEventSeasonalQuests(event_id, GetLastStartTime(event_id));
} }
void UpdateEventNPCFlags(ushort event_id) void UpdateEventNPCFlags(ushort event_id)
@@ -1676,6 +1676,21 @@ namespace Game
} }
} }
long GetLastStartTime(ushort event_id)
{
if (event_id >= mGameEvent.Length)
return 0;
if (mGameEvent[event_id].state != GameEventState.Normal)
return 0;
DateTime now = GameTime.GetSystemTime();
DateTime eventInitialStart = Time.UnixTimeToDateTime(mGameEvent[event_id].start);
TimeSpan occurence = TimeSpan.FromMinutes(mGameEvent[event_id].occurence);
TimeSpan durationSinceLastStart = TimeSpan.FromTicks((now - eventInitialStart).Ticks % occurence.Ticks);
return Time.DateTimeToUnixTime(now - durationSinceLastStart);
}
public bool IsHolidayActive(HolidayIds id) public bool IsHolidayActive(HolidayIds id)
{ {
if (id == HolidayIds.None) if (id == HolidayIds.None)
+3 -3
View File
@@ -2215,15 +2215,15 @@ namespace Game
SetWorldState(WorldStates.CurrencyResetTime, (ulong)m_NextCurrencyReset); SetWorldState(WorldStates.CurrencyResetTime, (ulong)m_NextCurrencyReset);
} }
public void ResetEventSeasonalQuests(ushort event_id) public void ResetEventSeasonalQuests(ushort event_id, long eventStartTime)
{ {
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_RESET_CHARACTER_QUESTSTATUS_SEASONAL_BY_EVENT); PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_RESET_CHARACTER_QUESTSTATUS_SEASONAL_BY_EVENT);
stmt.AddValue(0, event_id); stmt.AddValue(0, event_id);
stmt.AddValue(1, eventStartTime);
DB.Characters.Execute(stmt); DB.Characters.Execute(stmt);
foreach (var session in m_sessions.Values) foreach (var session in m_sessions.Values)
if (session.GetPlayer()) session.GetPlayer()?.ResetSeasonalQuestStatus(event_id, eventStartTime);
session.GetPlayer().ResetSeasonalQuestStatus(event_id);
} }
void ResetRandomBG() void ResetRandomBG()
+3 -1
View File
@@ -1426,6 +1426,7 @@ CREATE TABLE `character_queststatus_seasonal` (
`guid` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'Global Unique Identifier', `guid` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'Global Unique Identifier',
`quest` int unsigned NOT NULL DEFAULT '0' COMMENT 'Quest Identifier', `quest` int unsigned NOT NULL DEFAULT '0' COMMENT 'Quest Identifier',
`event` int unsigned NOT NULL DEFAULT '0' COMMENT 'Event Identifier', `event` int unsigned NOT NULL DEFAULT '0' COMMENT 'Event Identifier',
`completedTime` bigint NOT NULL DEFAULT '0',
PRIMARY KEY (`guid`,`quest`), PRIMARY KEY (`guid`,`quest`),
KEY `idx_guid` (`guid`) KEY `idx_guid` (`guid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Player System'; ) 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_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_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_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 */; /*!40000 ALTER TABLE `updates` ENABLE KEYS */;
UNLOCK TABLES; UNLOCK TABLES;
@@ -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;