aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2023-12-20 15:15:30 +0100
committerfunjoker <funjoker109@gmail.com>2023-12-21 00:13:10 +0100
commiteff969b2c6d529beb6b27aeabf765e166cb67e1b (patch)
treee57a10869ec9a2ce91821e470e5e053002586e44 /src
parent1c22646f5f0eb0dbb844e47effc90ec1d9982561 (diff)
Core/Quests: Fixed accessing freed memory after .reload quest_template
(cherry picked from commit 308a34ab41241022c7fd2fb42b0c6c9bad94f07e)
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Player/Player.cpp98
-rw-r--r--src/server/game/Entities/Player/Player.h2
2 files changed, 51 insertions, 49 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index cdb3285272a..f4a0ae6fc76 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -14432,7 +14432,7 @@ void Player::AddQuest(Quest const* quest, Object* questGiver)
for (QuestObjective const& obj : quest->GetObjectives())
{
- m_questObjectiveStatus.emplace(std::make_pair(QuestObjectiveType(obj.Type), obj.ObjectID), QuestObjectiveStatusData { questStatusItr, &obj });
+ m_questObjectiveStatus.emplace(std::make_pair(QuestObjectiveType(obj.Type), obj.ObjectID), QuestObjectiveStatusData { questStatusItr, obj.ID });
switch (obj.Type)
{
case QUEST_OBJECTIVE_MIN_REPUTATION:
@@ -16013,18 +16013,18 @@ void Player::ItemRemovedQuestCheck(uint32 entry, uint32 /*count*/)
for (QuestObjectiveStatusMap::value_type const& objectiveItr : Trinity::Containers::MapEqualRange(m_questObjectiveStatus, { QUEST_OBJECTIVE_ITEM, entry }))
{
uint32 questId = objectiveItr.second.QuestStatusItr->first;
- Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
uint16 logSlot = objectiveItr.second.QuestStatusItr->second.Slot;
- QuestObjective const& objective = *objectiveItr.second.Objective;
+ Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
+ QuestObjective const* objective = sObjectMgr->GetQuestObjective(objectiveItr.second.ObjectiveId);
- if (!IsQuestObjectiveCompletable(logSlot, quest, objective))
+ if (!quest || !objective || !IsQuestObjectiveCompletable(logSlot, quest, *objective))
continue;
int32 newItemCount = GetItemCount(entry, false); // we may have more than what the status shows, so we have to iterate inventory
- if (newItemCount < objective.Amount)
+ if (newItemCount < objective->Amount)
{
- SetQuestObjectiveData(objective, newItemCount);
+ SetQuestObjectiveData(*objective, newItemCount);
IncompleteQuest(questId);
}
}
@@ -16111,37 +16111,39 @@ void Player::UpdateQuestObjectiveProgress(QuestObjectiveType objectiveType, int3
{
uint32 questId = objectiveItr.second.QuestStatusItr->first;
Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
+ if (!quest)
+ continue;
if (!QuestObjective::CanAlwaysBeProgressedInRaid(objectiveType))
if (GetGroup() && GetGroup()->isRaidGroup() && !quest->IsAllowedInRaid(GetMap()->GetDifficultyID()))
continue;
uint16 logSlot = objectiveItr.second.QuestStatusItr->second.Slot;
- QuestObjective const& objective = *objectiveItr.second.Objective;
- if (!IsQuestObjectiveCompletable(logSlot, quest, objective))
+ QuestObjective const* objective = sObjectMgr->GetQuestObjective(objectiveItr.second.ObjectiveId);
+ if (!objective || !IsQuestObjectiveCompletable(logSlot, quest, *objective))
continue;
if (quest->HasFlagEx(QUEST_FLAGS_EX_NO_CREDIT_FOR_PROXY))
- if (objective.Type == QUEST_OBJECTIVE_MONSTER && victimGuid.IsEmpty())
+ if (objective->Type == QUEST_OBJECTIVE_MONSTER && victimGuid.IsEmpty())
continue;
- bool objectiveWasComplete = IsQuestObjectiveComplete(logSlot, quest, objective);
+ bool objectiveWasComplete = IsQuestObjectiveComplete(logSlot, quest, *objective);
if (!objectiveWasComplete || addCount < 0)
{
bool objectiveIsNowComplete = false;
- if (objective.IsStoringValue())
+ if (objective->IsStoringValue())
{
- if (objectiveType == QUEST_OBJECTIVE_PLAYERKILLS && objective.Flags & QUEST_OBJECTIVE_FLAG_KILL_PLAYERS_SAME_FACTION)
+ if (objectiveType == QUEST_OBJECTIVE_PLAYERKILLS && objective->Flags & QUEST_OBJECTIVE_FLAG_KILL_PLAYERS_SAME_FACTION)
if (Player const* victim = ObjectAccessor::GetPlayer(GetMap(), victimGuid))
if (victim->GetEffectiveTeam() != GetEffectiveTeam())
continue;
- int32 currentProgress = GetQuestSlotObjectiveData(logSlot, objective);
- if (addCount > 0 ? (currentProgress < objective.Amount) : (currentProgress > 0))
+ int32 currentProgress = GetQuestSlotObjectiveData(logSlot, *objective);
+ if (addCount > 0 ? (currentProgress < objective->Amount) : (currentProgress > 0))
{
- int32 newProgress = std::clamp<int32>(currentProgress + addCount, 0, objective.Amount);
- SetQuestObjectiveData(objective, newProgress);
- if (addCount > 0 && !(objective.Flags & QUEST_OBJECTIVE_FLAG_HIDE_CREDIT_MSG))
+ int32 newProgress = std::clamp<int32>(currentProgress + addCount, 0, objective->Amount);
+ SetQuestObjectiveData(*objective, newProgress);
+ if (addCount > 0 && !(objective->Flags & QUEST_OBJECTIVE_FLAG_HIDE_CREDIT_MSG))
{
switch (objectiveType)
{
@@ -16151,41 +16153,41 @@ void Player::UpdateQuestObjectiveProgress(QuestObjectiveType objectiveType, int3
SendQuestUpdateAddPlayer(quest, newProgress);
break;
default:
- SendQuestUpdateAddCredit(quest, victimGuid, objective, newProgress);
+ SendQuestUpdateAddCredit(quest, victimGuid, *objective, newProgress);
break;
}
}
- objectiveIsNowComplete = IsQuestObjectiveComplete(logSlot, quest, objective);
+ objectiveIsNowComplete = IsQuestObjectiveComplete(logSlot, quest, *objective);
}
}
- else if (objective.IsStoringFlag())
+ else if (objective->IsStoringFlag())
{
- SetQuestObjectiveData(objective, addCount > 0);
+ SetQuestObjectiveData(*objective, addCount > 0);
- if (addCount > 0 && !(objective.Flags & QUEST_OBJECTIVE_FLAG_HIDE_CREDIT_MSG))
- SendQuestUpdateAddCreditSimple(objective);
+ if (addCount > 0 && !(objective->Flags & QUEST_OBJECTIVE_FLAG_HIDE_CREDIT_MSG))
+ SendQuestUpdateAddCreditSimple(*objective);
- objectiveIsNowComplete = IsQuestObjectiveComplete(logSlot, quest, objective);
+ objectiveIsNowComplete = IsQuestObjectiveComplete(logSlot, quest, *objective);
}
else
{
switch (objectiveType)
{
case QUEST_OBJECTIVE_CURRENCY:
- objectiveIsNowComplete = GetCurrencyQuantity(objectId) + addCount >= objective.Amount;
+ objectiveIsNowComplete = GetCurrencyQuantity(objectId) + addCount >= objective->Amount;
break;
case QUEST_OBJECTIVE_LEARNSPELL:
objectiveIsNowComplete = addCount != 0;
break;
case QUEST_OBJECTIVE_MIN_REPUTATION:
- objectiveIsNowComplete = GetReputationMgr().GetReputation(objectId) + addCount >= objective.Amount;
+ objectiveIsNowComplete = GetReputationMgr().GetReputation(objectId) + addCount >= objective->Amount;
break;
case QUEST_OBJECTIVE_MAX_REPUTATION:
- objectiveIsNowComplete = GetReputationMgr().GetReputation(objectId) + addCount <= objective.Amount;
+ objectiveIsNowComplete = GetReputationMgr().GetReputation(objectId) + addCount <= objective->Amount;
break;
case QUEST_OBJECTIVE_MONEY:
- objectiveIsNowComplete = int64(GetMoney()) + addCount >= objective.Amount;
+ objectiveIsNowComplete = int64(GetMoney()) + addCount >= objective->Amount;
break;
case QUEST_OBJECTIVE_PROGRESS_BAR:
objectiveIsNowComplete = IsQuestObjectiveProgressBarComplete(logSlot, quest);
@@ -16196,7 +16198,7 @@ void Player::UpdateQuestObjectiveProgress(QuestObjectiveType objectiveType, int3
}
}
- if (objective.Flags & QUEST_OBJECTIVE_FLAG_PART_OF_PROGRESS_BAR)
+ if (objective->Flags & QUEST_OBJECTIVE_FLAG_PART_OF_PROGRESS_BAR)
{
if (IsQuestObjectiveProgressBarComplete(logSlot, quest))
{
@@ -16214,26 +16216,26 @@ void Player::UpdateQuestObjectiveProgress(QuestObjectiveType objectiveType, int3
if (objectiveWasComplete != objectiveIsNowComplete)
anyObjectiveChangedCompletionState = true;
- if (objectiveIsNowComplete && objective.CompletionEffect)
+ if (objectiveIsNowComplete && objective->CompletionEffect)
{
- if (objective.CompletionEffect->GameEventId)
- GameEvents::Trigger(*objective.CompletionEffect->GameEventId, this, nullptr);
- if (objective.CompletionEffect->SpellId)
- CastSpell(this, *objective.CompletionEffect->SpellId, true);
- if (objective.CompletionEffect->ConversationId)
- Conversation::CreateConversation(*objective.CompletionEffect->ConversationId, this, GetPosition(), GetGUID());
- if (objective.CompletionEffect->UpdatePhaseShift)
+ if (objective->CompletionEffect->GameEventId)
+ GameEvents::Trigger(*objective->CompletionEffect->GameEventId, this, nullptr);
+ if (objective->CompletionEffect->SpellId)
+ CastSpell(this, *objective->CompletionEffect->SpellId, true);
+ if (objective->CompletionEffect->ConversationId)
+ Conversation::CreateConversation(*objective->CompletionEffect->ConversationId, this, GetPosition(), GetGUID());
+ if (objective->CompletionEffect->UpdatePhaseShift)
updatePhaseShift = true;
- if (objective.CompletionEffect->UpdateZoneAuras)
+ if (objective->CompletionEffect->UpdateZoneAuras)
updateZoneAuras = true;
}
if (objectiveIsNowComplete)
{
- if (CanCompleteQuest(questId, objective.ID))
+ if (CanCompleteQuest(questId, objective->ID))
CompleteQuest(questId);
}
- else if (!(objective.Flags & QUEST_OBJECTIVE_FLAG_OPTIONAL) && objectiveItr.second.QuestStatusItr->second.Status == QUEST_STATUS_COMPLETE)
+ else if (!(objective->Flags & QUEST_OBJECTIVE_FLAG_OPTIONAL) && objectiveItr.second.QuestStatusItr->second.Status == QUEST_STATUS_COMPLETE)
IncompleteQuest(questId);
}
}
@@ -16256,9 +16258,9 @@ bool Player::HasQuestForItem(uint32 itemid) const
// Search incomplete objective first
for (QuestObjectiveStatusMap::value_type const& objectiveItr : Trinity::Containers::MapEqualRange(m_questObjectiveStatus, { QUEST_OBJECTIVE_ITEM, itemid }))
{
- Quest const* qInfo = ASSERT_NOTNULL(sObjectMgr->GetQuestTemplate(objectiveItr.second.QuestStatusItr->first));
- QuestObjective const& objective = *objectiveItr.second.Objective;
- if (!IsQuestObjectiveCompletable(objectiveItr.second.QuestStatusItr->second.Slot, qInfo, objective))
+ Quest const* qInfo = sObjectMgr->GetQuestTemplate(objectiveItr.second.QuestStatusItr->first);
+ QuestObjective const* objective = sObjectMgr->GetQuestObjective(objectiveItr.second.ObjectiveId);
+ if (!qInfo || !objective || !IsQuestObjectiveCompletable(objectiveItr.second.QuestStatusItr->second.Slot, qInfo, *objective))
continue;
// hide quest if player is in raid-group and quest is no raid quest
@@ -16266,7 +16268,7 @@ bool Player::HasQuestForItem(uint32 itemid) const
if (!InBattleground()) //there are two ways.. we can make every bg-quest a raidquest, or add this code here.. i don't know if this can be exploited by other quests, but i think all other quests depend on a specific area.. but keep this in mind, if something strange happens later
continue;
- if (!IsQuestObjectiveComplete(objectiveItr.second.QuestStatusItr->second.Slot, qInfo, objective))
+ if (!IsQuestObjectiveComplete(objectiveItr.second.QuestStatusItr->second.Slot, qInfo, *objective))
return true;
}
@@ -18536,7 +18538,7 @@ void Player::_LoadQuestStatus(PreparedQueryResult result)
questStatusData.Slot = slot;
for (QuestObjective const& obj : quest->GetObjectives())
- m_questObjectiveStatus.emplace(std::make_pair(QuestObjectiveType(obj.Type), obj.ObjectID), QuestObjectiveStatusData{ questStatusItr, &obj });
+ m_questObjectiveStatus.emplace(std::make_pair(QuestObjectiveType(obj.Type), obj.ObjectID), QuestObjectiveStatusData{ questStatusItr, obj.ID });
SetQuestSlot(slot, quest_id);
SetQuestSlotEndTime(slot, endTime);
@@ -24282,8 +24284,8 @@ bool Player::HasQuestForGO(int32 GOId) const
for (QuestObjectiveStatusMap::value_type const& objectiveItr : Trinity::Containers::MapEqualRange(m_questObjectiveStatus, { QUEST_OBJECTIVE_GAMEOBJECT, GOId }))
{
Quest const* qInfo = ASSERT_NOTNULL(sObjectMgr->GetQuestTemplate(objectiveItr.second.QuestStatusItr->first));
- QuestObjective const& objective = *objectiveItr.second.Objective;
- if (!IsQuestObjectiveCompletable(objectiveItr.second.QuestStatusItr->second.Slot, qInfo, objective))
+ QuestObjective const* objective = sObjectMgr->GetQuestObjective(objectiveItr.second.ObjectiveId);
+ if (!qInfo || !objective || !IsQuestObjectiveCompletable(objectiveItr.second.QuestStatusItr->second.Slot, qInfo, *objective))
continue;
// hide quest if player is in raid-group and quest is no raid quest
@@ -24291,7 +24293,7 @@ bool Player::HasQuestForGO(int32 GOId) const
if (!InBattleground()) //there are two ways.. we can make every bg-quest a raidquest, or add this code here.. i don't know if this can be exploited by other quests, but i think all other quests depend on a specific area.. but keep this in mind, if something strange happens later
continue;
- if (!IsQuestObjectiveComplete(objectiveItr.second.QuestStatusItr->second.Slot, qInfo, objective))
+ if (!IsQuestObjectiveComplete(objectiveItr.second.QuestStatusItr->second.Slot, qInfo, *objective))
return true;
}
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 66b4f913fcd..26318834d2a 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -547,7 +547,7 @@ typedef std::map<uint32, QuestStatusData> QuestStatusMap;
struct QuestObjectiveStatusData
{
QuestStatusMap::iterator QuestStatusItr;
- QuestObjective const* Objective;
+ uint32 ObjectiveId;
};
using QuestObjectiveStatusMap = std::unordered_multimap<std::pair<QuestObjectiveType, int32>, QuestObjectiveStatusData>;