diff options
author | Shauren <shauren.trinity@gmail.com> | 2024-01-11 20:56:24 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2024-01-11 20:56:24 +0100 |
commit | 0b5406dd882c6d96bc1be6fd0a78375c3b316415 (patch) | |
tree | 095fe9c5ebd20ae4163784b925f1dcd83b45f407 /src/server/game/Conditions | |
parent | 913d769b80bb2a5187c6df562ec013db540bf8ea (diff) |
Core/Conditions: Refactor ConditionMgr internals to get rid of separate containers for some condition source types
Diffstat (limited to 'src/server/game/Conditions')
-rw-r--r-- | src/server/game/Conditions/ConditionMgr.cpp | 676 | ||||
-rw-r--r-- | src/server/game/Conditions/ConditionMgr.h | 89 |
2 files changed, 315 insertions, 450 deletions
diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index f18af4a220b..9d11270d594 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -57,7 +57,7 @@ #include <random> #include <sstream> -char const* const ConditionMgr::StaticSourceTypeData[CONDITION_SOURCE_TYPE_MAX] = +char const* const ConditionMgr::StaticSourceTypeData[CONDITION_SOURCE_TYPE_MAX_DB_ALLOWED] = { "None", "Creature Loot", @@ -179,6 +179,15 @@ ConditionSourceInfo::ConditionSourceInfo(Map const* map) mLastFailedCondition = nullptr; } +std::size_t ConditionId::GetHash() const +{ + std::size_t hashVal = 0; + Trinity::hash_combine(hashVal, SourceGroup); + Trinity::hash_combine(hashVal, SourceEntry); + Trinity::hash_combine(hashVal, SourceId); + return hashVal; +} + // Checks if object meets the condition // Can have CONDITION_SOURCE_TYPE_NONE && !mReferenceId if called from a special event (ie: SmartAI) bool Condition::Meets(ConditionSourceInfo& sourceInfo) const @@ -904,8 +913,10 @@ std::string Condition::ToString(bool ext /*= false*/) const std::ostringstream ss; ss << "[Condition "; ss << "SourceType: " << SourceType; - if (SourceType < CONDITION_SOURCE_TYPE_MAX) + if (SourceType < CONDITION_SOURCE_TYPE_MAX_DB_ALLOWED) ss << " (" << ConditionMgr::StaticSourceTypeData[SourceType] << ")"; + else if (SourceType == CONDITION_SOURCE_TYPE_REFERENCE_CONDITION) + ss << " (Reference)"; else ss << " (Unknown)"; if (ConditionMgr::CanHaveSourceGroupSet(SourceType)) @@ -943,26 +954,26 @@ uint32 ConditionMgr::GetSearcherTypeMaskForConditionList(ConditionContainer cons for (ConditionContainer::const_iterator i = conditions.begin(); i != conditions.end(); ++i) { // no point of having not loaded conditions in list - ASSERT((*i)->isLoaded() && "ConditionMgr::GetSearcherTypeMaskForConditionList - not yet loaded condition found in list"); - std::map<uint32, uint32>::const_iterator itr = elseGroupSearcherTypeMasks.find((*i)->ElseGroup); + ASSERT(i->isLoaded() && "ConditionMgr::GetSearcherTypeMaskForConditionList - not yet loaded condition found in list"); + std::map<uint32, uint32>::const_iterator itr = elseGroupSearcherTypeMasks.find(i->ElseGroup); // group not filled yet, fill with widest mask possible if (itr == elseGroupSearcherTypeMasks.end()) - elseGroupSearcherTypeMasks[(*i)->ElseGroup] = GRID_MAP_TYPE_MASK_ALL; + elseGroupSearcherTypeMasks[i->ElseGroup] = GRID_MAP_TYPE_MASK_ALL; // no point of checking anymore, empty mask else if (!itr->second) continue; - if ((*i)->ReferenceId) // handle reference + if (i->ReferenceId) // handle reference { - ConditionReferenceContainer::const_iterator ref = ConditionReferenceStore.find((*i)->ReferenceId); - ASSERT(ref != ConditionReferenceStore.end() && "ConditionMgr::GetSearcherTypeMaskForConditionList - incorrect reference"); - elseGroupSearcherTypeMasks[(*i)->ElseGroup] &= GetSearcherTypeMaskForConditionList((*ref).second); + auto ref = ConditionStore[CONDITION_SOURCE_TYPE_REFERENCE_CONDITION].find({ i->ReferenceId, 0, 0 }); + ASSERT(ref != ConditionStore[CONDITION_SOURCE_TYPE_REFERENCE_CONDITION].end() && "ConditionMgr::GetSearcherTypeMaskForConditionList - incorrect reference"); + elseGroupSearcherTypeMasks[i->ElseGroup] &= GetSearcherTypeMaskForConditionList(*(ref->second)); } else // handle normal condition { // object will match conditions in one ElseGroupStore only when it matches all of them // so, let's find a smallest possible mask which satisfies all conditions - elseGroupSearcherTypeMasks[(*i)->ElseGroup] &= (*i)->GetSearcherTypeMaskForCondition(); + elseGroupSearcherTypeMasks[i->ElseGroup] &= i->GetSearcherTypeMaskForCondition(); } } // object will match condition when one of the checks in ElseGroupStore is matching @@ -978,38 +989,35 @@ bool ConditionMgr::IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo, { // groupId, groupCheckPassed std::map<uint32, bool> elseGroupStore; - for (Condition const* condition : conditions) + for (Condition const& condition : conditions) { - TC_LOG_DEBUG("condition", "ConditionMgr::IsPlayerMeetToConditionList {} val1: {}", condition->ToString(), condition->ConditionValue1); - if (condition->isLoaded()) + TC_LOG_DEBUG("condition", "ConditionMgr::IsPlayerMeetToConditionList {} val1: {}", condition.ToString(), condition.ConditionValue1); + if (condition.isLoaded()) { //! Find ElseGroup in ElseGroupStore - std::map<uint32, bool>::const_iterator itr = elseGroupStore.find(condition->ElseGroup); - //! If not found, add an entry in the store and set to true (placeholder) - if (itr == elseGroupStore.end()) - elseGroupStore[condition->ElseGroup] = true; - else if (!(*itr).second) //! If another condition in this group was unmatched before this, don't bother checking (the group is false anyway) + std::map<uint32, bool>::iterator itr = elseGroupStore.try_emplace(condition.ElseGroup, true).first; + if (!itr->second) //! If another condition in this group was unmatched before this, don't bother checking (the group is false anyway) continue; - if (condition->ReferenceId)//handle reference + if (condition.ReferenceId)//handle reference { - ConditionReferenceContainer::const_iterator ref = ConditionReferenceStore.find(condition->ReferenceId); - if (ref != ConditionReferenceStore.end()) + auto ref = ConditionStore[CONDITION_SOURCE_TYPE_REFERENCE_CONDITION].find({ condition.ReferenceId, 0, 0 }); + if (ref != ConditionStore[CONDITION_SOURCE_TYPE_REFERENCE_CONDITION].end()) { - if (!IsObjectMeetToConditionList(sourceInfo, ref->second)) - elseGroupStore[condition->ElseGroup] = false; + if (!IsObjectMeetToConditionList(sourceInfo, *ref->second)) + itr->second = false; } else { TC_LOG_DEBUG("condition", "ConditionMgr::IsPlayerMeetToConditionList {} Reference template -{} not found", - condition->ToString(), condition->ReferenceId); // checked at loading, should never happen + condition.ToString(), condition.ReferenceId); // checked at loading, should never happen } } else //handle normal condition { - if (!condition->Meets(sourceInfo)) - elseGroupStore[condition->ElseGroup] = false; + if (!condition.Meets(sourceInfo)) + itr->second = false; } } } @@ -1066,7 +1074,8 @@ bool ConditionMgr::CanHaveSourceGroupSet(ConditionSourceType sourceType) sourceType == CONDITION_SOURCE_TYPE_GRAVEYARD || sourceType == CONDITION_SOURCE_TYPE_AREATRIGGER || sourceType == CONDITION_SOURCE_TYPE_TRAINER_SPELL || - sourceType == CONDITION_SOURCE_TYPE_OBJECT_ID_VISIBILITY); + sourceType == CONDITION_SOURCE_TYPE_OBJECT_ID_VISIBILITY || + sourceType == CONDITION_SOURCE_TYPE_REFERENCE_CONDITION); } bool ConditionMgr::CanHaveSourceIdSet(ConditionSourceType sourceType) @@ -1104,11 +1113,11 @@ bool ConditionMgr::IsObjectMeetingNotGroupedConditions(ConditionSourceType sourc { if (sourceType > CONDITION_SOURCE_TYPE_NONE && sourceType < CONDITION_SOURCE_TYPE_MAX) { - ConditionsByEntryMap::const_iterator i = ConditionStore[sourceType].find(entry); + auto i = ConditionStore[sourceType].find({ 0, int32(entry), 0 }); if (i != ConditionStore[sourceType].end()) { TC_LOG_DEBUG("condition", "GetConditionsForNotGroupedEntry: found conditions for type {} and entry {}", uint32(sourceType), entry); - return IsObjectMeetToConditions(sourceInfo, i->second); + return IsObjectMeetToConditions(sourceInfo, *i->second); } } @@ -1130,87 +1139,66 @@ bool ConditionMgr::IsMapMeetingNotGroupedConditions(ConditionSourceType sourceTy bool ConditionMgr::HasConditionsForNotGroupedEntry(ConditionSourceType sourceType, uint32 entry) const { if (sourceType > CONDITION_SOURCE_TYPE_NONE && sourceType < CONDITION_SOURCE_TYPE_MAX) - if (ConditionStore[sourceType].find(entry) != ConditionStore[sourceType].end()) - return true; + return ConditionStore[sourceType].contains({ 0, int32(entry), 0 }); return false; } bool ConditionMgr::IsObjectMeetingSpellClickConditions(uint32 creatureId, uint32 spellId, WorldObject const* clicker, WorldObject const* target) const { - ConditionEntriesByCreatureIdMap::const_iterator itr = SpellClickEventConditionStore.find(creatureId); - if (itr != SpellClickEventConditionStore.end()) + auto itr = ConditionStore[CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT].find({ creatureId, int32(spellId), 0 }); + if (itr != ConditionStore[CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT].end()) { - ConditionsByEntryMap::const_iterator i = itr->second.find(spellId); - if (i != itr->second.end()) - { - TC_LOG_DEBUG("condition", "GetConditionsForSpellClickEvent: found conditions for SpellClickEvent entry {} spell {}", creatureId, spellId); - ConditionSourceInfo sourceInfo(clicker, target); - return IsObjectMeetToConditions(sourceInfo, i->second); - } + TC_LOG_DEBUG("condition", "IsObjectMeetingSpellClickConditions: found conditions for SpellClickEvent entry {} spell {}", creatureId, spellId); + ConditionSourceInfo sourceInfo(clicker, target); + return IsObjectMeetToConditions(sourceInfo, *itr->second); } return true; } -ConditionContainer const* ConditionMgr::GetConditionsForSpellClickEvent(uint32 creatureId, uint32 spellId) const +bool ConditionMgr::HasConditionsForSpellClickEvent(uint32 creatureId, uint32 spellId) const { - ConditionEntriesByCreatureIdMap::const_iterator itr = SpellClickEventConditionStore.find(creatureId); - if (itr != SpellClickEventConditionStore.end()) + auto itr = ConditionStore[CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT].find({ creatureId, int32(spellId), 0 }); + if (itr != ConditionStore[CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT].end()) { - ConditionsByEntryMap::const_iterator i = itr->second.find(spellId); - if (i != itr->second.end()) - { - TC_LOG_DEBUG("condition", "GetConditionsForSpellClickEvent: found conditions for SpellClickEvent entry {} spell {}", creatureId, spellId); - return &i->second; - } + TC_LOG_DEBUG("condition", "HasConditionsForSpellClickEvent: found conditions for SpellClickEvent entry {} spell {}", creatureId, spellId); + return true; } - return nullptr; + return false; } bool ConditionMgr::IsObjectMeetingVehicleSpellConditions(uint32 creatureId, uint32 spellId, Player const* player, Unit const* vehicle) const { - ConditionEntriesByCreatureIdMap::const_iterator itr = VehicleSpellConditionStore.find(creatureId); - if (itr != VehicleSpellConditionStore.end()) + auto itr = ConditionStore[CONDITION_SOURCE_TYPE_VEHICLE_SPELL].find({ creatureId, int32(spellId), 0 }); + if (itr != ConditionStore[CONDITION_SOURCE_TYPE_VEHICLE_SPELL].end()) { - ConditionsByEntryMap::const_iterator i = itr->second.find(spellId); - if (i != itr->second.end()) - { - TC_LOG_DEBUG("condition", "GetConditionsForVehicleSpell: found conditions for Vehicle entry {} spell {}", creatureId, spellId); - ConditionSourceInfo sourceInfo(player, vehicle); - return IsObjectMeetToConditions(sourceInfo, i->second); - } + TC_LOG_DEBUG("condition", "GetConditionsForVehicleSpell: found conditions for Vehicle entry {} spell {}", creatureId, spellId); + ConditionSourceInfo sourceInfo(player, vehicle); + return IsObjectMeetToConditions(sourceInfo, *itr->second); } return true; } bool ConditionMgr::IsObjectMeetingSmartEventConditions(int64 entryOrGuid, uint32 eventId, uint32 sourceType, Unit const* unit, WorldObject const* baseObject) const { - SmartEventConditionContainer::const_iterator itr = SmartEventConditionStore.find(std::make_pair(entryOrGuid, sourceType)); - if (itr != SmartEventConditionStore.end()) + auto itr = ConditionStore[CONDITION_SOURCE_TYPE_SMART_EVENT].find({ eventId + 1, int32(entryOrGuid), sourceType }); + if (itr != ConditionStore[CONDITION_SOURCE_TYPE_SMART_EVENT].end()) { - ConditionsByEntryMap::const_iterator i = itr->second.find(eventId + 1); - if (i != itr->second.end()) - { - TC_LOG_DEBUG("condition", "GetConditionsForSmartEvent: found conditions for Smart Event entry or guid {} eventId {}", entryOrGuid, eventId); - ConditionSourceInfo sourceInfo(unit, baseObject); - return IsObjectMeetToConditions(sourceInfo, i->second); - } + TC_LOG_DEBUG("condition", "GetConditionsForSmartEvent: found conditions for Smart Event entry or guid {} eventId {}", entryOrGuid, eventId); + ConditionSourceInfo sourceInfo(unit, baseObject); + return IsObjectMeetToConditions(sourceInfo, *itr->second); } return true; } bool ConditionMgr::IsObjectMeetingVendorItemConditions(uint32 creatureId, uint32 itemId, Player const* player, Creature const* vendor) const { - ConditionEntriesByCreatureIdMap::const_iterator itr = NpcVendorConditionContainerStore.find(creatureId); - if (itr != NpcVendorConditionContainerStore.end()) + auto itr = ConditionStore[CONDITION_SOURCE_TYPE_NPC_VENDOR].find({ creatureId, int32(itemId), 0 }); + if (itr != ConditionStore[CONDITION_SOURCE_TYPE_NPC_VENDOR].end()) { - ConditionsByEntryMap::const_iterator i = (*itr).second.find(itemId); - if (i != (*itr).second.end()) - { - TC_LOG_DEBUG("condition", "GetConditionsForNpcVendor: found conditions for creature entry {} item {}", creatureId, itemId); - ConditionSourceInfo sourceInfo(player, vendor); - return IsObjectMeetToConditions(sourceInfo, i->second); - } + TC_LOG_DEBUG("condition", "GetConditionsForNpcVendor: found conditions for creature entry {} item {}", creatureId, itemId); + ConditionSourceInfo sourceInfo(player, vendor); + return IsObjectMeetToConditions(sourceInfo, *itr->second); } return true; } @@ -1222,30 +1210,30 @@ bool ConditionMgr::IsSpellUsedInSpellClickConditions(uint32 spellId) const ConditionContainer const* ConditionMgr::GetConditionsForAreaTrigger(uint32 areaTriggerId, bool isServerSide) const { - return Trinity::Containers::MapGetValuePtr(AreaTriggerConditionContainerStore, { areaTriggerId, isServerSide }); + auto itr = ConditionStore[CONDITION_SOURCE_TYPE_AREATRIGGER].find({ areaTriggerId, isServerSide ? 1 : 0, 0 }); + if (itr != ConditionStore[CONDITION_SOURCE_TYPE_AREATRIGGER].end()) + return itr->second.get(); + return nullptr; } bool ConditionMgr::IsObjectMeetingTrainerSpellConditions(uint32 trainerId, uint32 spellId, Player* player) const { - ConditionEntriesByCreatureIdMap::const_iterator itr = TrainerSpellConditionContainerStore.find(trainerId); - if (itr != TrainerSpellConditionContainerStore.end()) + auto itr = ConditionStore[CONDITION_SOURCE_TYPE_NPC_VENDOR].find({ trainerId, int32(spellId), 0 }); + if (itr != ConditionStore[CONDITION_SOURCE_TYPE_NPC_VENDOR].end()) { - ConditionsByEntryMap::const_iterator i = (*itr).second.find(spellId); - if (i != (*itr).second.end()) - { - TC_LOG_DEBUG("condition", "GetConditionsForTrainerSpell: found conditions for trainer id {} spell {}", trainerId, spellId); - return IsObjectMeetToConditions(player, i->second); - } + TC_LOG_DEBUG("condition", "IsObjectMeetingTrainerSpellConditions: found conditions for trainer id {} spell {}", trainerId, spellId); + return IsObjectMeetToConditions(player, *itr->second); } return true; } bool ConditionMgr::IsObjectMeetingVisibilityByObjectIdConditions(uint32 objectType, uint32 entry, WorldObject const* seer) const { - if (ConditionContainer const* conditions = Trinity::Containers::MapGetValuePtr(ObjectVisibilityConditionStore, { objectType, entry })) + auto itr = ConditionStore[CONDITION_SOURCE_TYPE_OBJECT_ID_VISIBILITY].find({ objectType, int32(entry), 0 }); + if (itr != ConditionStore[CONDITION_SOURCE_TYPE_OBJECT_ID_VISIBILITY].end()) { TC_LOG_DEBUG("condition", "IsObjectMeetingVisibilityByObjectIdConditions: found conditions for objectType {} entry {}", objectType, entry); - return IsObjectMeetToConditions(seer, *conditions); + return IsObjectMeetToConditions(seer, *itr->second); } return true; } @@ -1265,26 +1253,6 @@ void ConditionMgr::LoadConditions(bool isReload) //must clear all custom handled cases (groupped types) before reload if (isReload) { - TC_LOG_INFO("misc", "Reseting Loot Conditions..."); - LootTemplates_Creature.ResetConditions(); - LootTemplates_Fishing.ResetConditions(); - LootTemplates_Gameobject.ResetConditions(); - LootTemplates_Item.ResetConditions(); - LootTemplates_Mail.ResetConditions(); - LootTemplates_Milling.ResetConditions(); - LootTemplates_Pickpocketing.ResetConditions(); - LootTemplates_Reference.ResetConditions(); - LootTemplates_Skinning.ResetConditions(); - LootTemplates_Disenchant.ResetConditions(); - LootTemplates_Prospecting.ResetConditions(); - LootTemplates_Spell.ResetConditions(); - - TC_LOG_INFO("misc", "Re-Loading `gossip_menu` Table for Conditions!"); - sObjectMgr->LoadGossipMenu(); - - TC_LOG_INFO("misc", "Re-Loading `gossip_menu_option` Table for Conditions!"); - sObjectMgr->LoadGossipMenuItems(); - sSpellMgr->UnloadSpellInfoImplicitTargetConditionLists(); sObjectMgr->UnloadPhaseConditions(); @@ -1301,330 +1269,256 @@ void ConditionMgr::LoadConditions(bool isReload) uint32 count = 0; + auto getOrInitConditions = [this](ConditionSourceType sourceType, ConditionId const& id) + { + auto [itr, inserted] = ConditionStore[sourceType].try_emplace(id, nullptr); + if (inserted) + itr->second = std::make_shared<std::vector<Condition>>(); + return itr->second; + }; + do { Field* fields = result->Fetch(); - Condition* cond = new Condition(); + Condition cond; int32 iSourceTypeOrReferenceId = fields[0].GetInt32(); - cond->SourceGroup = fields[1].GetUInt32(); - cond->SourceEntry = fields[2].GetInt32(); - cond->SourceId = fields[3].GetInt32(); - cond->ElseGroup = fields[4].GetUInt32(); + cond.SourceGroup = fields[1].GetUInt32(); + cond.SourceEntry = fields[2].GetInt32(); + cond.SourceId = fields[3].GetInt32(); + cond.ElseGroup = fields[4].GetUInt32(); int32 iConditionTypeOrReference = fields[5].GetInt32(); - cond->ConditionTarget = fields[6].GetUInt8(); - cond->ConditionValue1 = fields[7].GetUInt32(); - cond->ConditionValue2 = fields[8].GetUInt32(); - cond->ConditionValue3 = fields[9].GetUInt32(); - cond->NegativeCondition = fields[10].GetBool(); - cond->ErrorType = fields[11].GetUInt32(); - cond->ErrorTextId = fields[12].GetUInt32(); - cond->ScriptId = sObjectMgr->GetScriptId(fields[13].GetString()); + cond.ConditionTarget = fields[6].GetUInt8(); + cond.ConditionValue1 = fields[7].GetUInt32(); + cond.ConditionValue2 = fields[8].GetUInt32(); + cond.ConditionValue3 = fields[9].GetUInt32(); + cond.NegativeCondition = fields[10].GetBool(); + cond.ErrorType = fields[11].GetUInt32(); + cond.ErrorTextId = fields[12].GetUInt32(); + cond.ScriptId = sObjectMgr->GetScriptId(fields[13].GetString()); if (iConditionTypeOrReference >= 0) - cond->ConditionType = ConditionTypes(iConditionTypeOrReference); + cond.ConditionType = ConditionTypes(iConditionTypeOrReference); if (iSourceTypeOrReferenceId >= 0) - cond->SourceType = ConditionSourceType(iSourceTypeOrReferenceId); + cond.SourceType = ConditionSourceType(iSourceTypeOrReferenceId); if (iConditionTypeOrReference < 0)//it has a reference { if (iConditionTypeOrReference == iSourceTypeOrReferenceId)//self referencing, skip { TC_LOG_ERROR("sql.sql", "Condition reference {} is referencing self, skipped", iSourceTypeOrReferenceId); - delete cond; continue; } - cond->ReferenceId = uint32(abs(iConditionTypeOrReference)); + + cond.ReferenceId = uint32(-iConditionTypeOrReference); char const* rowType = "reference template"; if (iSourceTypeOrReferenceId >= 0) rowType = "reference"; //check for useless data - if (cond->ConditionTarget) - TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in ConditionTarget ({})!", rowType, iSourceTypeOrReferenceId, cond->ConditionTarget); - if (cond->ConditionValue1) - TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in value1 ({})!", rowType, iSourceTypeOrReferenceId, cond->ConditionValue1); - if (cond->ConditionValue2) - TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in value2 ({})!", rowType, iSourceTypeOrReferenceId, cond->ConditionValue2); - if (cond->ConditionValue3) - TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in value3 ({})!", rowType, iSourceTypeOrReferenceId, cond->ConditionValue3); - if (cond->NegativeCondition) - TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in NegativeCondition ({})!", rowType, iSourceTypeOrReferenceId, cond->NegativeCondition); - if (cond->SourceGroup && iSourceTypeOrReferenceId < 0) - TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in SourceGroup ({})!", rowType, iSourceTypeOrReferenceId, cond->SourceGroup); - if (cond->SourceEntry && iSourceTypeOrReferenceId < 0) - TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in SourceEntry ({})!", rowType, iSourceTypeOrReferenceId, cond->SourceEntry); - } - else if (!isConditionTypeValid(cond))//doesn't have reference, validate ConditionType - { - delete cond; + if (cond.ConditionTarget) + TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in ConditionTarget ({})!", rowType, iSourceTypeOrReferenceId, cond.ConditionTarget); + if (cond.ConditionValue1) + TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in value1 ({})!", rowType, iSourceTypeOrReferenceId, cond.ConditionValue1); + if (cond.ConditionValue2) + TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in value2 ({})!", rowType, iSourceTypeOrReferenceId, cond.ConditionValue2); + if (cond.ConditionValue3) + TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in value3 ({})!", rowType, iSourceTypeOrReferenceId, cond.ConditionValue3); + if (cond.NegativeCondition) + TC_LOG_ERROR("sql.sql", "Condition {} {} has useless data in NegativeCondition ({})!", rowType, iSourceTypeOrReferenceId, cond.NegativeCondition); + } + else if (!isConditionTypeValid(&cond))//doesn't have reference, validate ConditionType continue; - } if (iSourceTypeOrReferenceId < 0)//it is a reference template { - ConditionReferenceStore[std::abs(iSourceTypeOrReferenceId)].push_back(cond);//add to reference storage - ++count; - continue; - }//end of reference templates + if (cond.SourceGroup) + TC_LOG_ERROR("sql.sql", "Condition reference template {} has useless data in SourceGroup ({})!", iSourceTypeOrReferenceId, cond.SourceGroup); + if (cond.SourceEntry) + TC_LOG_ERROR("sql.sql", "Condition reference template {} has useless data in SourceEntry ({})!", iSourceTypeOrReferenceId, cond.SourceEntry); + if (cond.SourceId) + TC_LOG_ERROR("sql.sql", "Condition reference template {} has useless data in SourceId ({})!", iSourceTypeOrReferenceId, cond.SourceId); - //if not a reference and SourceType is invalid, skip - if (iConditionTypeOrReference >= 0 && !isSourceTypeValid(cond)) - { - delete cond; - continue; + cond.SourceType = CONDITION_SOURCE_TYPE_REFERENCE_CONDITION; + cond.SourceGroup = -iSourceTypeOrReferenceId; } + else if (!isSourceTypeValid(&cond)) //if not a reference and SourceType is invalid, skip + continue; //Grouping is only allowed for some types (loot templates, gossip menus, gossip items) - if (cond->SourceGroup && !CanHaveSourceGroupSet(cond->SourceType)) + if (cond.SourceGroup && !CanHaveSourceGroupSet(cond.SourceType)) { - TC_LOG_ERROR("sql.sql", "{} has not allowed value of SourceGroup = {}!", cond->ToString(), cond->SourceGroup); - delete cond; + TC_LOG_ERROR("sql.sql", "{} has not allowed value of SourceGroup = {}!", cond.ToString(), cond.SourceGroup); continue; } - if (cond->SourceId && !CanHaveSourceIdSet(cond->SourceType)) + if (cond.SourceId && !CanHaveSourceIdSet(cond.SourceType)) { - TC_LOG_ERROR("sql.sql", "{} has not allowed value of SourceId = {}!", cond->ToString(), cond->SourceId); - delete cond; + TC_LOG_ERROR("sql.sql", "{} has not allowed value of SourceId = {}!", cond.ToString(), cond.SourceId); continue; } - if (cond->ErrorType && cond->SourceType != CONDITION_SOURCE_TYPE_SPELL) - { - TC_LOG_ERROR("sql.sql", "{} can't have ErrorType ({}), set to 0!", cond->ToString(), cond->ErrorType); - cond->ErrorType = 0; - } - - if (cond->ErrorTextId && !cond->ErrorType) + if (cond.ErrorType && cond.SourceType != CONDITION_SOURCE_TYPE_SPELL) { - TC_LOG_ERROR("sql.sql", "{} has any ErrorType, ErrorTextId ({}) is set, set to 0!", cond->ToString(), cond->ErrorTextId); - cond->ErrorTextId = 0; + TC_LOG_ERROR("sql.sql", "{} can't have ErrorType ({}), set to 0!", cond.ToString(), cond.ErrorType); + cond.ErrorType = 0; } - if (cond->SourceGroup) + if (cond.ErrorTextId && !cond.ErrorType) { - bool valid = false; - // handle grouped conditions - switch (cond->SourceType) - { - case CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE: - valid = addToLootTemplate(cond, LootTemplates_Creature.GetLootForConditionFill(cond->SourceGroup)); - break; - case CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE: - valid = addToLootTemplate(cond, LootTemplates_Disenchant.GetLootForConditionFill(cond->SourceGroup)); - break; - case CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE: - valid = addToLootTemplate(cond, LootTemplates_Fishing.GetLootForConditionFill(cond->SourceGroup)); - break; - case CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE: - valid = addToLootTemplate(cond, LootTemplates_Gameobject.GetLootForConditionFill(cond->SourceGroup)); - break; - case CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE: - valid = addToLootTemplate(cond, LootTemplates_Item.GetLootForConditionFill(cond->SourceGroup)); - break; - case CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE: - valid = addToLootTemplate(cond, LootTemplates_Mail.GetLootForConditionFill(cond->SourceGroup)); - break; - case CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE: - valid = addToLootTemplate(cond, LootTemplates_Milling.GetLootForConditionFill(cond->SourceGroup)); - break; - case CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE: - valid = addToLootTemplate(cond, LootTemplates_Pickpocketing.GetLootForConditionFill(cond->SourceGroup)); - break; - case CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE: - valid = addToLootTemplate(cond, LootTemplates_Prospecting.GetLootForConditionFill(cond->SourceGroup)); - break; - case CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE: - valid = addToLootTemplate(cond, LootTemplates_Reference.GetLootForConditionFill(cond->SourceGroup)); - break; - case CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE: - valid = addToLootTemplate(cond, LootTemplates_Skinning.GetLootForConditionFill(cond->SourceGroup)); - break; - case CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE: - valid = addToLootTemplate(cond, LootTemplates_Spell.GetLootForConditionFill(cond->SourceGroup)); - break; - case CONDITION_SOURCE_TYPE_GOSSIP_MENU: - valid = addToGossipMenus(cond); - break; - case CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION: - valid = addToGossipMenuItems(cond); - break; - case CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT: - { - SpellClickEventConditionStore[cond->SourceGroup][cond->SourceEntry].push_back(cond); - if (cond->ConditionType == CONDITION_AURA) - SpellsUsedInSpellClickConditions.insert(cond->ConditionValue1); - valid = true; - ++count; - continue; // do not add to m_AllocatedMemory to avoid double deleting - } - case CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET: - valid = addToSpellImplicitTargetConditions(cond); - break; - case CONDITION_SOURCE_TYPE_VEHICLE_SPELL: - { - VehicleSpellConditionStore[cond->SourceGroup][cond->SourceEntry].push_back(cond); - valid = true; - ++count; - continue; // do not add to m_AllocatedMemory to avoid double deleting - } - case CONDITION_SOURCE_TYPE_SMART_EVENT: - { - //! TODO: PAIR_32 ? - std::pair<int32, uint32> key = std::make_pair(cond->SourceEntry, cond->SourceId); - SmartEventConditionStore[key][cond->SourceGroup].push_back(cond); - valid = true; - ++count; - continue; - } - case CONDITION_SOURCE_TYPE_NPC_VENDOR: - { - NpcVendorConditionContainerStore[cond->SourceGroup][cond->SourceEntry].push_back(cond); - valid = true; - ++count; - continue; - } - case CONDITION_SOURCE_TYPE_PHASE: - valid = addToPhases(cond); - break; - case CONDITION_SOURCE_TYPE_GRAVEYARD: - valid = addToGraveyardData(cond); - break; - case CONDITION_SOURCE_TYPE_AREATRIGGER: - { - AreaTriggerConditionContainerStore[{ cond->SourceGroup, cond->SourceEntry }].push_back(cond); - valid = true; - ++count; - continue; - } - case CONDITION_SOURCE_TYPE_TRAINER_SPELL: - { - TrainerSpellConditionContainerStore[cond->SourceGroup][cond->SourceEntry].push_back(cond); - valid = true; - ++count; - continue; - } - case CONDITION_SOURCE_TYPE_OBJECT_ID_VISIBILITY: - { - ObjectVisibilityConditionStore[{ cond->SourceGroup, uint32(cond->SourceEntry) }].push_back(cond); - valid = true; - ++count; - continue; - } - default: - break; - } - - if (!valid) - { - TC_LOG_ERROR("sql.sql", "{} Not handled grouped condition.", cond->ToString()); - delete cond; - } - else - { - AllocatedMemoryStore.push_back(cond); - ++count; - } - continue; + TC_LOG_ERROR("sql.sql", "{} has any ErrorType, ErrorTextId ({}) is set, set to 0!", cond.ToString(), cond.ErrorTextId); + cond.ErrorTextId = 0; } - //handle not grouped conditions - //add new Condition to storage based on Type/Entry - if (cond->SourceType == CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT && cond->ConditionType == CONDITION_AURA) - SpellsUsedInSpellClickConditions.insert(cond->ConditionValue1); - ConditionStore[cond->SourceType][cond->SourceEntry].push_back(cond); + getOrInitConditions(cond.SourceType, { cond.SourceGroup, cond.SourceEntry, cond.SourceId })->emplace_back(std::move(cond)); ++count; } while (result->NextRow()); + for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE]) + addToLootTemplate(id, conditions, LootTemplates_Creature.GetLootForConditionFill(id.SourceGroup)); + + for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE]) + addToLootTemplate(id, conditions, LootTemplates_Disenchant.GetLootForConditionFill(id.SourceGroup)); + + for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE]) + addToLootTemplate(id, conditions, LootTemplates_Fishing.GetLootForConditionFill(id.SourceGroup)); + + for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE]) + addToLootTemplate(id, conditions, LootTemplates_Gameobject.GetLootForConditionFill(id.SourceGroup)); + + for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE]) + addToLootTemplate(id, conditions, LootTemplates_Item.GetLootForConditionFill(id.SourceGroup)); + + for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE]) + addToLootTemplate(id, conditions, LootTemplates_Mail.GetLootForConditionFill(id.SourceGroup)); + + for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE]) + addToLootTemplate(id, conditions, LootTemplates_Milling.GetLootForConditionFill(id.SourceGroup)); + + for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE]) + addToLootTemplate(id, conditions, LootTemplates_Pickpocketing.GetLootForConditionFill(id.SourceGroup)); + + for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE]) + addToLootTemplate(id, conditions, LootTemplates_Prospecting.GetLootForConditionFill(id.SourceGroup)); + + for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE]) + addToLootTemplate(id, conditions, LootTemplates_Reference.GetLootForConditionFill(id.SourceGroup)); + + for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE]) + addToLootTemplate(id, conditions, LootTemplates_Skinning.GetLootForConditionFill(id.SourceGroup)); + + for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE]) + addToLootTemplate(id, conditions, LootTemplates_Spell.GetLootForConditionFill(id.SourceGroup)); + + for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_GOSSIP_MENU]) + addToGossipMenus(id, conditions); + + for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION]) + addToGossipMenuItems(id, conditions); + + SpellsUsedInSpellClickConditions.clear(); + for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT]) + for (Condition const& condition : *conditions) + if (condition.ConditionType == CONDITION_AURA) + SpellsUsedInSpellClickConditions.insert(condition.ConditionValue1); + + for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET]) + for (Condition const& condition : *conditions) + addToSpellImplicitTargetConditions(condition); + + for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_PHASE]) + addToPhases(id, conditions); + + for (auto&& [id, conditions] : ConditionStore[CONDITION_SOURCE_TYPE_GRAVEYARD]) + addToGraveyardData(id, conditions); + TC_LOG_INFO("server.loading", ">> Loaded {} conditions in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); } -bool ConditionMgr::addToLootTemplate(Condition* cond, LootTemplate* loot) const +void ConditionMgr::addToLootTemplate(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions, LootTemplate* loot) const { if (!loot) { - TC_LOG_ERROR("sql.sql", "{} LootTemplate {} not found.", cond->ToString(), cond->SourceGroup); - return false; + for (Condition const& condition : *conditions) + TC_LOG_ERROR("sql.sql", "{} LootTemplate {} not found.", condition.ToString(), id.SourceGroup); + return; } - if (loot->addConditionItem(cond)) - return true; + if (loot->LinkConditions(id, ConditionsReference{ conditions })) + return; - TC_LOG_ERROR("sql.sql", "{} Item {} not found in LootTemplate {}.", cond->ToString(), cond->SourceEntry, cond->SourceGroup); - return false; + for (Condition const& condition : *conditions) + TC_LOG_ERROR("sql.sql", "{} Item {} not found in LootTemplate {}.", condition.ToString(), id.SourceEntry, id.SourceGroup); } -bool ConditionMgr::addToGossipMenus(Condition* cond) const +void ConditionMgr::addToGossipMenus(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const { - GossipMenusMapBoundsNonConst pMenuBounds = sObjectMgr->GetGossipMenusMapBoundsNonConst(cond->SourceGroup); + GossipMenusMapBoundsNonConst pMenuBounds = sObjectMgr->GetGossipMenusMapBoundsNonConst(id.SourceGroup); if (pMenuBounds.first != pMenuBounds.second) { for (GossipMenusContainer::iterator itr = pMenuBounds.first; itr != pMenuBounds.second; ++itr) - { - if (itr->second.MenuID == cond->SourceGroup && (itr->second.TextID == uint32(cond->SourceEntry) || cond->SourceEntry == 0)) - itr->second.Conditions.push_back(cond); - } - return true; + if (itr->second.MenuID == id.SourceGroup && (itr->second.TextID == uint32(id.SourceEntry) || id.SourceEntry == 0)) + itr->second.Conditions = { conditions }; + + return; } - TC_LOG_ERROR("sql.sql", "{} GossipMenu {} not found.", cond->ToString(), cond->SourceGroup); - return false; + for (Condition const& condition : *conditions) + TC_LOG_ERROR("sql.sql", "{} GossipMenu {} not found.", condition.ToString(), id.SourceGroup); } -bool ConditionMgr::addToGossipMenuItems(Condition* cond) const +void ConditionMgr::addToGossipMenuItems(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const { - Trinity::IteratorPair pMenuItemBounds = sObjectMgr->GetGossipMenuItemsMapBoundsNonConst(cond->SourceGroup); + Trinity::IteratorPair pMenuItemBounds = sObjectMgr->GetGossipMenuItemsMapBoundsNonConst(id.SourceGroup); for (auto& [_, gossipMenuItem] : pMenuItemBounds) { - if (gossipMenuItem.MenuID == cond->SourceGroup && gossipMenuItem.OrderIndex == uint32(cond->SourceEntry)) + if (gossipMenuItem.MenuID == id.SourceGroup && gossipMenuItem.OrderIndex == uint32(id.SourceEntry)) { - gossipMenuItem.Conditions.push_back(cond); - return true; + gossipMenuItem.Conditions = { conditions }; + return; } } - TC_LOG_ERROR("sql.sql", "{} GossipMenuId {} Item {} not found.", cond->ToString(), cond->SourceGroup, cond->SourceEntry); - return false; + for (Condition const& condition : *conditions) + TC_LOG_ERROR("sql.sql", "{} GossipMenuId {} Item {} not found.", condition.ToString(), id.SourceGroup, id.SourceEntry); } -bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond) const +void ConditionMgr::addToSpellImplicitTargetConditions(Condition const& cond) const { - bool valid = false; - sSpellMgr->ForEachSpellInfoDifficulty(cond->SourceEntry, [&](SpellInfo const* spellInfo) + sSpellMgr->ForEachSpellInfoDifficulty(cond.SourceEntry, [&](SpellInfo const* spellInfo) { - uint32 conditionEffMask = cond->SourceGroup; + uint32 conditionEffMask = cond.SourceGroup; std::list<uint32> sharedMasks; for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects()) { // additional checks by condition type if (conditionEffMask & (1 << spellEffectInfo.EffectIndex)) { - switch (cond->ConditionType) + switch (cond.ConditionType) { case CONDITION_OBJECT_ENTRY_GUID: { uint32 implicitTargetMask = GetTargetFlagMask(spellEffectInfo.TargetA.GetObjectType()) | GetTargetFlagMask(spellEffectInfo.TargetB.GetObjectType()); - if ((implicitTargetMask & TARGET_FLAG_UNIT_MASK) && cond->ConditionValue1 != TYPEID_UNIT && cond->ConditionValue1 != TYPEID_PLAYER) + if ((implicitTargetMask & TARGET_FLAG_UNIT_MASK) && cond.ConditionValue1 != TYPEID_UNIT && cond.ConditionValue1 != TYPEID_PLAYER) { TC_LOG_ERROR("sql.sql", "{} in `condition` table - spell {} EFFECT_{} - " - "target requires ConditionValue1 to be either TYPEID_UNIT ({}) or TYPEID_PLAYER ({})", cond->ToString(), spellInfo->Id, uint32(spellEffectInfo.EffectIndex), uint32(TYPEID_UNIT), uint32(TYPEID_PLAYER)); + "target requires ConditionValue1 to be either TYPEID_UNIT ({}) or TYPEID_PLAYER ({})", cond.ToString(), spellInfo->Id, uint32(spellEffectInfo.EffectIndex), uint32(TYPEID_UNIT), uint32(TYPEID_PLAYER)); return; } - if ((implicitTargetMask & TARGET_FLAG_GAMEOBJECT_MASK) && cond->ConditionValue1 != TYPEID_GAMEOBJECT) + if ((implicitTargetMask & TARGET_FLAG_GAMEOBJECT_MASK) && cond.ConditionValue1 != TYPEID_GAMEOBJECT) { TC_LOG_ERROR("sql.sql", "{} in `condition` table - spell {} EFFECT_{} - " - "target requires ConditionValue1 to be TYPEID_GAMEOBJECT ({})", cond->ToString(), spellInfo->Id, uint32(spellEffectInfo.EffectIndex), uint32(TYPEID_GAMEOBJECT)); + "target requires ConditionValue1 to be TYPEID_GAMEOBJECT ({})", cond.ToString(), spellInfo->Id, uint32(spellEffectInfo.EffectIndex), uint32(TYPEID_GAMEOBJECT)); return; } - if ((implicitTargetMask & TARGET_FLAG_CORPSE_MASK) && cond->ConditionValue1 != TYPEID_CORPSE) + if ((implicitTargetMask & TARGET_FLAG_CORPSE_MASK) && cond.ConditionValue1 != TYPEID_CORPSE) { TC_LOG_ERROR("sql.sql", "{} in `condition` table - spell {} EFFECT_{} - " - "target requires ConditionValue1 to be TYPEID_CORPSE ({})", cond->ToString(), spellInfo->Id, uint32(spellEffectInfo.EffectIndex), uint32(TYPEID_CORPSE)); + "target requires ConditionValue1 to be TYPEID_CORPSE ({})", cond.ToString(), spellInfo->Id, uint32(spellEffectInfo.EffectIndex), uint32(TYPEID_CORPSE)); return; } break; @@ -1641,9 +1535,8 @@ bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond) const // build new shared mask with found effect uint32 sharedMask = 1 << spellEffectInfo.EffectIndex; - ConditionContainer* cmp = spellEffectInfo.ImplicitTargetConditions; for (size_t effIndex = spellEffectInfo.EffectIndex + 1; effIndex < spellInfo->GetEffects().size(); ++effIndex) - if (spellInfo->GetEffect(SpellEffIndex(effIndex)).ImplicitTargetConditions == cmp) + if (spellInfo->GetEffect(SpellEffIndex(effIndex)).ImplicitTargetConditions == spellEffectInfo.ImplicitTargetConditions) sharedMask |= 1 << effIndex; sharedMasks.push_back(sharedMask); @@ -1663,7 +1556,7 @@ bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond) const return; // get shared data - ConditionContainer* sharedList = spellInfo->GetEffect(SpellEffIndex(firstEffIndex)).ImplicitTargetConditions; + std::shared_ptr<ConditionContainer> sharedList = spellInfo->GetEffect(SpellEffIndex(firstEffIndex)).ImplicitTargetConditions; // there's already data entry for that sharedMask if (sharedList) @@ -1673,7 +1566,7 @@ bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond) const { TC_LOG_ERROR("sql.sql", "{} in `condition` table, has incorrect SourceGroup {} (spell effectMask) set - " "effect masks are overlapping (all SourceGroup values having given bit set must be equal) - ignoring (Difficulty {}).", - cond->ToString(), cond->SourceGroup, uint32(spellInfo->Difficulty)); + cond.ToString(), cond.SourceGroup, uint32(spellInfo->Difficulty)); return; } } @@ -1681,7 +1574,7 @@ bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond) const else { // add new list, create new shared mask - sharedList = new ConditionContainer(); + sharedList = std::make_shared<ConditionContainer>(); bool assigned = false; for (size_t i = firstEffIndex; i < spellInfo->GetEffects().size(); ++i) { @@ -1693,25 +1586,20 @@ bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond) const } if (!assigned) - { - delete sharedList; break; - } } sharedList->push_back(cond); break; } } - valid = true; }); - return true; } -bool ConditionMgr::addToPhases(Condition* cond) const +void ConditionMgr::addToPhases(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const { - if (!cond->SourceEntry) + if (!id.SourceEntry) { - if (PhaseInfoStruct const* phaseInfo = sObjectMgr->GetPhaseInfo(cond->SourceGroup)) + if (PhaseInfoStruct const* phaseInfo = sObjectMgr->GetPhaseInfo(id.SourceGroup)) { bool found = false; for (uint32 areaId : phaseInfo->Areas) @@ -1720,9 +1608,9 @@ bool ConditionMgr::addToPhases(Condition* cond) const { for (PhaseAreaInfo& phase : *phases) { - if (phase.PhaseInfo->Id == cond->SourceGroup) + if (phase.PhaseInfo->Id == id.SourceGroup) { - phase.Conditions.push_back(cond); + phase.Conditions.insert(phase.Conditions.end(), conditions->begin(), conditions->end()); found = true; } } @@ -1730,35 +1618,35 @@ bool ConditionMgr::addToPhases(Condition* cond) const } if (found) - return true; + return; } } - else if (std::vector<PhaseAreaInfo>* phases = const_cast<std::vector<PhaseAreaInfo>*>(sObjectMgr->GetPhasesForArea(cond->SourceEntry))) + else if (std::vector<PhaseAreaInfo>* phases = const_cast<std::vector<PhaseAreaInfo>*>(sObjectMgr->GetPhasesForArea(id.SourceEntry))) { for (PhaseAreaInfo& phase : *phases) { - if (phase.PhaseInfo->Id == cond->SourceGroup) + if (phase.PhaseInfo->Id == id.SourceGroup) { - phase.Conditions.push_back(cond); - return true; + phase.Conditions.insert(phase.Conditions.end(), conditions->begin(), conditions->end()); + return; } } } - TC_LOG_ERROR("sql.sql", "{} Area {} does not have phase {}.", cond->ToString(), cond->SourceEntry, cond->SourceGroup); - return false; + for (Condition const& condition : *conditions) + TC_LOG_ERROR("sql.sql", "{} Area {} does not have phase {}.", condition.ToString(), id.SourceEntry, id.SourceGroup); } -bool ConditionMgr::addToGraveyardData(Condition* cond) const +void ConditionMgr::addToGraveyardData(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const { - if (GraveyardData* graveyard = const_cast<GraveyardData*>(sObjectMgr->FindGraveyardData(cond->SourceEntry, cond->SourceGroup))) + if (GraveyardData* graveyard = const_cast<GraveyardData*>(sObjectMgr->FindGraveyardData(id.SourceEntry, id.SourceGroup))) { - graveyard->Conditions.push_back(cond); - return true; + graveyard->Conditions = { conditions }; + return; } - TC_LOG_ERROR("sql.sql", "{}, Graveyard {} does not have ghostzone {}.", cond->ToString(), cond->SourceEntry, cond->SourceGroup); - return false; + for (Condition const& condition : *conditions) + TC_LOG_ERROR("sql.sql", "{}, Graveyard {} does not have ghostzone {}.", condition.ToString(), id.SourceEntry, id.SourceGroup); } bool ConditionMgr::isSourceTypeValid(Condition* cond) const @@ -2146,7 +2034,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) const TC_LOG_ERROR("sql.sql", "{} in `condition` table, unexpected SourceEntry value (expected 0 or 1), ignoring.", cond->ToString()); return false; } - if (!sAreaTriggerDataStore->GetAreaTriggerTemplate({ uint32(cond->SourceGroup), bool(cond->SourceEntry) })) + if (!sAreaTriggerDataStore->GetAreaTriggerTemplate({ uint32(cond->SourceGroup), cond->SourceEntry == 1 })) { TC_LOG_ERROR("sql.sql", "{} in `condition` table, does not exist in `areatrigger_template`, ignoring.", cond->ToString()); return false; @@ -2815,74 +2703,10 @@ void ConditionMgr::LogUselessConditionValue(Condition* cond, uint8 index, uint32 void ConditionMgr::Clean() { - for (ConditionReferenceContainer::iterator itr = ConditionReferenceStore.begin(); itr != ConditionReferenceStore.end(); ++itr) - for (ConditionContainer::const_iterator it = itr->second.begin(); it != itr->second.end(); ++it) - delete *it; - - ConditionReferenceStore.clear(); - - for (uint32 i = 0; i < CONDITION_SOURCE_TYPE_MAX; ++i) - { - for (ConditionsByEntryMap::iterator it = ConditionStore[i].begin(); it != ConditionStore[i].end(); ++it) - for (ConditionContainer::const_iterator itr = it->second.begin(); itr != it->second.end(); ++itr) - delete *itr; + for (std::unordered_map<ConditionId, std::shared_ptr<std::vector<Condition>>>& conditionsMap : ConditionStore) + conditionsMap.clear(); - ConditionStore[i].clear(); - } - - for (ConditionEntriesByCreatureIdMap::iterator itr = VehicleSpellConditionStore.begin(); itr != VehicleSpellConditionStore.end(); ++itr) - for (ConditionsByEntryMap::iterator it = itr->second.begin(); it != itr->second.end(); ++it) - for (ConditionContainer::const_iterator i = it->second.begin(); i != it->second.end(); ++i) - delete *i; - - VehicleSpellConditionStore.clear(); - - for (SmartEventConditionContainer::iterator itr = SmartEventConditionStore.begin(); itr != SmartEventConditionStore.end(); ++itr) - for (ConditionsByEntryMap::iterator it = itr->second.begin(); it != itr->second.end(); ++it) - for (ConditionContainer::const_iterator i = it->second.begin(); i != it->second.end(); ++i) - delete *i; - - SmartEventConditionStore.clear(); - - for (ConditionEntriesByCreatureIdMap::iterator itr = SpellClickEventConditionStore.begin(); itr != SpellClickEventConditionStore.end(); ++itr) - for (ConditionsByEntryMap::iterator it = itr->second.begin(); it != itr->second.end(); ++it) - for (ConditionContainer::const_iterator i = it->second.begin(); i != it->second.end(); ++i) - delete *i; - - SpellClickEventConditionStore.clear(); SpellsUsedInSpellClickConditions.clear(); - - for (ConditionEntriesByCreatureIdMap::iterator itr = NpcVendorConditionContainerStore.begin(); itr != NpcVendorConditionContainerStore.end(); ++itr) - for (ConditionsByEntryMap::iterator it = itr->second.begin(); it != itr->second.end(); ++it) - for (ConditionContainer::const_iterator i = it->second.begin(); i != it->second.end(); ++i) - delete *i; - - NpcVendorConditionContainerStore.clear(); - - for (ConditionEntriesByAreaTriggerIdMap::iterator itr = AreaTriggerConditionContainerStore.begin(); itr != AreaTriggerConditionContainerStore.end(); ++itr) - for (ConditionContainer::const_iterator i = itr->second.begin(); i != itr->second.end(); ++i) - delete *i; - - AreaTriggerConditionContainerStore.clear(); - - for (ConditionEntriesByCreatureIdMap::iterator itr = TrainerSpellConditionContainerStore.begin(); itr != TrainerSpellConditionContainerStore.end(); ++itr) - for (ConditionsByEntryMap::iterator it = itr->second.begin(); it != itr->second.end(); ++it) - for (ConditionContainer::const_iterator i = it->second.begin(); i != it->second.end(); ++i) - delete *i; - - TrainerSpellConditionContainerStore.clear(); - - for (auto&& [_, conditions] : ObjectVisibilityConditionStore) - for (Condition* condition : conditions) - delete condition; - - ObjectVisibilityConditionStore.clear(); - - // this is a BIG hack, feel free to fix it if you can figure out the ConditionMgr ;) - for (std::vector<Condition*>::const_iterator itr = AllocatedMemoryStore.begin(); itr != AllocatedMemoryStore.end(); ++itr) - delete *itr; - - AllocatedMemoryStore.clear(); } inline bool PlayerConditionCompare(int32 comparisonType, int32 value1, int32 value2) diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h index e7e94cc3a54..cedc07ed67c 100644 --- a/src/server/game/Conditions/ConditionMgr.h +++ b/src/server/game/Conditions/ConditionMgr.h @@ -21,6 +21,7 @@ #include "Define.h" #include "Hash.h" #include <array> +#include <memory> #include <string> #include <unordered_map> #include <unordered_set> @@ -183,7 +184,10 @@ enum ConditionSourceType CONDITION_SOURCE_TYPE_TRAINER_SPELL = 31, CONDITION_SOURCE_TYPE_OBJECT_ID_VISIBILITY = 32, CONDITION_SOURCE_TYPE_SPAWN_GROUP = 33, - CONDITION_SOURCE_TYPE_MAX = 34 // MAX + + CONDITION_SOURCE_TYPE_MAX_DB_ALLOWED, + CONDITION_SOURCE_TYPE_REFERENCE_CONDITION = CONDITION_SOURCE_TYPE_MAX_DB_ALLOWED, // internal, not set in db + CONDITION_SOURCE_TYPE_MAX // MAX }; enum RelationType @@ -219,6 +223,23 @@ struct TC_GAME_API ConditionSourceInfo ConditionSourceInfo(Map const* map); }; +struct TC_GAME_API ConditionId +{ + uint32 SourceGroup = 0; + int32 SourceEntry = 0; + uint32 SourceId = 0; + + std::size_t GetHash() const; + bool operator==(ConditionId const& right) const = default; + std::strong_ordering operator<=>(ConditionId const& right) const = default; +}; + +template<> +struct std::hash<ConditionId> +{ + std::size_t operator()(ConditionId const& id) const noexcept { return id.GetHash(); } +}; + struct TC_GAME_API Condition { ConditionSourceType SourceType; //SourceTypeOrReferenceId @@ -264,13 +285,9 @@ struct TC_GAME_API Condition std::string ToString(bool ext = false) const; /// For logging purpose }; -typedef std::vector<Condition*> ConditionContainer; -typedef std::unordered_map<uint32 /*SourceEntry*/, ConditionContainer> ConditionsByEntryMap; +typedef std::vector<Condition> ConditionContainer; +typedef std::unordered_map<ConditionId, std::shared_ptr<ConditionContainer>> ConditionsByEntryMap; // stored as shared_ptr to give out weak_ptrs to hold by other code (ownership not shared) typedef std::array<ConditionsByEntryMap, CONDITION_SOURCE_TYPE_MAX> ConditionEntriesByTypeArray; -typedef std::unordered_map<uint32, ConditionsByEntryMap> ConditionEntriesByCreatureIdMap; -typedef std::unordered_map<std::pair<int32, uint32 /*SAI source_type*/>, ConditionsByEntryMap> SmartEventConditionContainer; -typedef std::unordered_map<uint32, ConditionContainer> ConditionReferenceContainer;//only used for references -typedef std::unordered_map<std::pair<int32, bool>, ConditionContainer> ConditionEntriesByAreaTriggerIdMap; class TC_GAME_API ConditionMgr { @@ -296,7 +313,7 @@ class TC_GAME_API ConditionMgr bool IsMapMeetingNotGroupedConditions(ConditionSourceType sourceType, uint32 entry, Map const* map) const; bool HasConditionsForNotGroupedEntry(ConditionSourceType sourceType, uint32 entry) const; bool IsObjectMeetingSpellClickConditions(uint32 creatureId, uint32 spellId, WorldObject const* clicker, WorldObject const* target) const; - ConditionContainer const* GetConditionsForSpellClickEvent(uint32 creatureId, uint32 spellId) const; + bool HasConditionsForSpellClickEvent(uint32 creatureId, uint32 spellId) const; bool IsObjectMeetingVehicleSpellConditions(uint32 creatureId, uint32 spellId, Player const* player, Unit const* vehicle) const; bool IsObjectMeetingSmartEventConditions(int64 entryOrGuid, uint32 eventId, uint32 sourceType, Unit const* unit, WorldObject const* baseObject) const; bool IsObjectMeetingVendorItemConditions(uint32 creatureId, uint32 itemId, Player const* player, Creature const* vendor) const; @@ -319,37 +336,61 @@ class TC_GAME_API ConditionMgr bool HasConditionValue2; bool HasConditionValue3; }; - static char const* const StaticSourceTypeData[CONDITION_SOURCE_TYPE_MAX]; + static char const* const StaticSourceTypeData[CONDITION_SOURCE_TYPE_MAX_DB_ALLOWED]; static ConditionTypeInfo const StaticConditionTypeData[CONDITION_MAX]; private: bool isSourceTypeValid(Condition* cond) const; - bool addToLootTemplate(Condition* cond, LootTemplate* loot) const; - bool addToGossipMenus(Condition* cond) const; - bool addToGossipMenuItems(Condition* cond) const; - bool addToSpellImplicitTargetConditions(Condition* cond) const; - bool addToPhases(Condition* cond) const; - bool addToGraveyardData(Condition* cond) const; + void addToLootTemplate(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions, LootTemplate* loot) const; + void addToGossipMenus(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const; + void addToGossipMenuItems(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const; + void addToSpellImplicitTargetConditions(Condition const& cond) const; + void addToPhases(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const; + void addToGraveyardData(ConditionId const& id, std::shared_ptr<std::vector<Condition>> conditions) const; bool IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo, ConditionContainer const& conditions) const; static void LogUselessConditionValue(Condition* cond, uint8 index, uint32 value); void Clean(); // free up resources - std::vector<Condition*> AllocatedMemoryStore; // some garbage collection :) ConditionEntriesByTypeArray ConditionStore; - ConditionReferenceContainer ConditionReferenceStore; - ConditionEntriesByCreatureIdMap VehicleSpellConditionStore; - ConditionEntriesByCreatureIdMap SpellClickEventConditionStore; - ConditionEntriesByCreatureIdMap NpcVendorConditionContainerStore; - SmartEventConditionContainer SmartEventConditionStore; std::unordered_set<uint32> SpellsUsedInSpellClickConditions; - ConditionEntriesByAreaTriggerIdMap AreaTriggerConditionContainerStore; - ConditionEntriesByCreatureIdMap TrainerSpellConditionContainerStore; - std::unordered_map<std::pair<uint32 /*object type*/, uint32 /*object id*/>, ConditionContainer> ObjectVisibilityConditionStore; }; #define sConditionMgr ConditionMgr::instance() +struct ConditionsReference +{ + bool Meets(WorldObject const* object) const + { + if (std::shared_ptr<std::vector<Condition>> conditions = Conditions.lock()) + return sConditionMgr->IsObjectMeetToConditions(object, *conditions); + return true; + } + + bool Meets(WorldObject const* object1, WorldObject const* object2) const + { + if (std::shared_ptr<std::vector<Condition>> conditions = Conditions.lock()) + return sConditionMgr->IsObjectMeetToConditions(object1, object2, *conditions); + return true; + } + + bool Meets(ConditionSourceInfo& sourceInfo) const + { + if (std::shared_ptr<std::vector<Condition>> conditions = Conditions.lock()) + return sConditionMgr->IsObjectMeetToConditions(sourceInfo, *conditions); + return true; + } + + bool IsEmpty() const + { + if (std::shared_ptr<std::vector<Condition>> conditions = Conditions.lock()) + return conditions->empty(); + return true; + } + + std::weak_ptr<ConditionContainer> Conditions; +}; + #endif |