Core/Quests: Fixed accessing freed memory after .reload quest_template

(cherry picked from commit 308a34ab41)
This commit is contained in:
Shauren
2023-12-20 15:15:30 +01:00
committed by funjoker
parent 1c22646f5f
commit eff969b2c6
2 changed files with 51 additions and 49 deletions

View File

@@ -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;
}

View File

@@ -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>;