diff --git a/Source/Game/Entities/Player/Player.DB.cs b/Source/Game/Entities/Player/Player.DB.cs index 2792c3c98..9978d79c1 100644 --- a/Source/Game/Entities/Player/Player.DB.cs +++ b/Source/Game/Entities/Player/Player.DB.cs @@ -721,6 +721,10 @@ namespace Game.Entities void _LoadQuestStatus(SQLResult result) { ushort slot = 0; + + long lastDailyReset = Global.WorldMgr.GetNextDailyQuestsResetTime() - Time.Day; + long lastWeeklyReset = Global.WorldMgr.GetNextWeeklyQuestsResetTime() - Time.Week; + if (!result.IsEmpty()) { do @@ -728,64 +732,73 @@ namespace Game.Entities uint questId = result.Read(0); // used to be new, no delete? Quest quest = Global.ObjectMgr.GetQuestTemplate(questId); - if (quest != null) + if (quest == null) + continue; + + // find or create + QuestStatusData questStatusData = new(); + + QuestStatus qstatus = (QuestStatus)result.Read(1); + if (qstatus < QuestStatus.Max) + questStatusData.Status = qstatus; + else { - // find or create - QuestStatusData questStatusData = new(); - - byte qstatus = result.Read(1); - if (qstatus < (byte)QuestStatus.Max) - questStatusData.Status = (QuestStatus)qstatus; - else - { - questStatusData.Status = QuestStatus.Incomplete; - Log.outError(LogFilter.Player, "Player {0} (GUID: {1}) has invalid quest {2} status ({3}), replaced by QUEST_STATUS_INCOMPLETE(3).", - GetName(), GetGUID().ToString(), questId, qstatus); - } - - questStatusData.Explored = result.Read(2) > 0; - - long acceptTime = result.Read(3); - long endTime = result.Read(4); - - if (quest.LimitTime != 0 && !GetQuestRewardStatus(questId)) - { - AddTimedQuest(questId); - - if (endTime <= GameTime.GetGameTime()) - questStatusData.Timer = 1; - else - questStatusData.Timer = (uint)((endTime - GameTime.GetGameTime()) * Time.InMilliseconds); - } - else - endTime = 0; - - // add to quest log - if (slot < SharedConst.MaxQuestLogSize && questStatusData.Status != QuestStatus.None) - { - questStatusData.Slot = slot; - - foreach (QuestObjective obj in quest.Objectives) - m_questObjectiveStatus.Add((obj.Type, obj.ObjectID), new QuestObjectiveStatusData() { QuestStatusPair = (questId, questStatusData), ObjectiveId = obj.Id }); - - SetQuestSlot(slot, questId); - SetQuestSlotEndTime(slot, endTime); - questStatusData.AcceptTime = acceptTime; - - if (questStatusData.Status == QuestStatus.Complete) - SetQuestSlotState(slot, QuestSlotStateMask.Complete); - else if (questStatusData.Status == QuestStatus.Failed) - SetQuestSlotState(slot, QuestSlotStateMask.Fail); - - if (quest.HasFlagEx(QuestFlagsEx.RecastAcceptSpellOnLogin) && quest.HasFlag(QuestFlags.PlayerCastAccept) && quest.SourceSpellID > 0) - CastSpell(this, quest.SourceSpellID, new CastSpellExtraArgs(TriggerCastFlags.FullMask)); - - ++slot; - } - - m_QuestStatus[questId] = questStatusData; - Log.outDebug(LogFilter.ServerLoading, "Quest status is {0} for quest {1} for player (GUID: {2})", questStatusData.Status, questId, GetGUID().ToString()); + questStatusData.Status = QuestStatus.Incomplete; + Log.outError(LogFilter.Player, $"Player._LoadQuestStatus: Player '{GetName()}' ({GetGUID()}) has invalid quest {questId} status ({qstatus}), replaced by QUEST_STATUS_INCOMPLETE(3)."); } + + questStatusData.Explored = result.Read(2) > 0; + + questStatusData.AcceptTime = result.Read(3); + if (quest.HasFlagEx(QuestFlagsEx.RemoveOnPeriodicReset)) + { + if ((quest.IsDaily() && questStatusData.AcceptTime < lastDailyReset) + || (quest.IsWeekly() && questStatusData.AcceptTime < lastWeeklyReset)) + { + questStatusData.Status = QuestStatus.None; + m_QuestStatusSave[questId] = QuestSaveType.Delete; + SendPacket(new QuestForceRemoved(questId)); + } + } + + long endTime = result.Read(4); + if (quest.LimitTime != 0 && !GetQuestRewardStatus(questId)) + { + AddTimedQuest(questId); + + if (endTime <= GameTime.GetGameTime()) + questStatusData.Timer = 1; + else + questStatusData.Timer = (uint)((endTime - GameTime.GetGameTime()) * Time.InMilliseconds); + } + else + endTime = 0; + + // add to quest log + if (slot < SharedConst.MaxQuestLogSize && questStatusData.Status != QuestStatus.None) + { + questStatusData.Slot = slot; + + foreach (QuestObjective obj in quest.Objectives) + m_questObjectiveStatus.Add((obj.Type, obj.ObjectID), new QuestObjectiveStatusData() { QuestStatusPair = (questId, questStatusData), ObjectiveId = obj.Id }); + + SetQuestSlot(slot, questId); + SetQuestSlotEndTime(slot, endTime); + + if (questStatusData.Status == QuestStatus.Complete) + SetQuestSlotState(slot, QuestSlotStateMask.Complete); + else if (questStatusData.Status == QuestStatus.Failed) + SetQuestSlotState(slot, QuestSlotStateMask.Fail); + + if (quest.HasFlagEx(QuestFlagsEx.RecastAcceptSpellOnLogin) && quest.HasFlag(QuestFlags.PlayerCastAccept) && quest.SourceSpellID > 0) + CastSpell(this, quest.SourceSpellID, new CastSpellExtraArgs(TriggerCastFlags.FullMask)); + + ++slot; + } + + m_QuestStatus[questId] = questStatusData; + Log.outDebug(LogFilter.ServerLoading, "Quest status is {0} for quest {1} for player (GUID: {2})", questStatusData.Status, questId, GetGUID().ToString()); + } while (result.NextRow()); } diff --git a/Source/Game/Entities/Player/Player.Quest.cs b/Source/Game/Entities/Player/Player.Quest.cs index af7810c1a..d2fe61f72 100644 --- a/Source/Game/Entities/Player/Player.Quest.cs +++ b/Source/Game/Entities/Player/Player.Quest.cs @@ -187,6 +187,8 @@ namespace Game.Entities if (quest.LimitTime != 0) RemoveTimedQuest(questId); + + SendPacket(new QuestForceRemoved(questId)); } // DB data deleted in caller @@ -227,6 +229,8 @@ namespace Game.Entities if (quest.LimitTime != 0) RemoveTimedQuest(questId); + + SendPacket(new QuestForceRemoved(questId)); } m_weeklyquests.Clear(); diff --git a/Source/Game/Networking/Packets/QuestPackets.cs b/Source/Game/Networking/Packets/QuestPackets.cs index 7bd34eb94..a29b05281 100644 --- a/Source/Game/Networking/Packets/QuestPackets.cs +++ b/Source/Game/Networking/Packets/QuestPackets.cs @@ -43,7 +43,7 @@ namespace Game.Networking.Packets QuestGiverGUIDs.Add(_worldPacket.ReadPackedGuid()); } } - + public class QuestGiverStatusPkt : ServerPacket { public QuestGiverStatusPkt() : base(ServerOpcodes.QuestGiverStatus, ConnectionType.Instance) @@ -440,7 +440,7 @@ namespace Game.Networking.Packets public uint QuestID; } - + public class QuestGiverQuestDetails : ServerPacket { public QuestGiverQuestDetails() : base(ServerOpcodes.QuestGiverQuestDetails) { } @@ -848,6 +848,21 @@ namespace Game.Networking.Packets public override void Write() { } } + class QuestForceRemoved : ServerPacket + { + uint QuestID; + + public QuestForceRemoved(uint questId) : base(ServerOpcodes.QuestForceRemoved) + { + QuestID = questId; + } + + public override void Write() + { + _worldPacket.WriteUInt32(QuestID); + } + } + class RequestWorldQuestUpdate : ClientPacket { public RequestWorldQuestUpdate(WorldPacket packet) : base(packet) { } @@ -1038,7 +1053,7 @@ namespace Game.Networking.Packets public float POIx; public float POIy; public uint POIPriority; - public RaceMask AllowableRaces = new (0xFFFFFFFFFFFFFFFF); + public RaceMask AllowableRaces = new(0xFFFFFFFFFFFFFFFF); public string LogTitle; public string LogDescription; public string QuestDescription; @@ -1372,7 +1387,7 @@ namespace Game.Networking.Packets } class PlayerChoiceResponse - { + { public int ResponseID; public ushort ResponseIdentifier; public int ChoiceArtFileID; diff --git a/Source/Game/World/WorldManager.cs b/Source/Game/World/WorldManager.cs index e397cf6bb..20739dc38 100644 --- a/Source/Game/World/WorldManager.cs +++ b/Source/Game/World/WorldManager.cs @@ -2016,17 +2016,6 @@ namespace Game player.DailyReset(); } - StringBuilder questIds = new StringBuilder("DELETE cq, cqo FROM character_queststatus cq LEFT JOIN character_queststatus_objectives cqo ON cq.quest = cqo.quest WHERE cq.quest IN ("); - foreach (var (questId, quest) in Global.ObjectMgr.GetQuestTemplates()) - { - if (quest.IsDaily() && quest.HasFlagEx(QuestFlagsEx.RemoveOnPeriodicReset)) - questIds.Append($"{questId},"); - } - questIds.Append("0)"); - - DB.Characters.Execute(questIds.ToString()); - - // reselect pools Global.QuestPoolMgr.ChangeDailyQuests(); @@ -2069,16 +2058,6 @@ namespace Game player.ResetWeeklyQuestStatus(); } - StringBuilder questIds = new StringBuilder("DELETE cq, cqo FROM character_queststatus cq LEFT JOIN character_queststatus_objectives cqo ON cq.quest = cqo.quest WHERE cq.quest IN ("); - foreach (var (questId, quest) in Global.ObjectMgr.GetQuestTemplates()) - { - if (quest.IsWeekly() && quest.HasFlagEx(QuestFlagsEx.RemoveOnWeeklyReset)) - questIds.Append($"{questId},"); - } - questIds.Append("0)"); - - DB.Characters.Execute(questIds.ToString()); - // reselect pools Global.QuestPoolMgr.ChangeWeeklyQuests();