diff options
author | Shauren <shauren.trinity@gmail.com> | 2024-08-04 18:24:10 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2024-08-04 18:24:10 +0200 |
commit | a7c8ac3505cb7e177b6f5299989d544a3b8cade9 (patch) | |
tree | 8cc8e91b4882a63d6cfdc48c63e52b33440fef81 /src/server/game/Spells/TraitMgr.cpp | |
parent | b0b81dd31badd6e25f36a74bb519da9097e36ec1 (diff) |
Core/Players: Fixed trait configs getting into invalid state after talent tree changes between client patches
Closes #29398
Diffstat (limited to 'src/server/game/Spells/TraitMgr.cpp')
-rw-r--r-- | src/server/game/Spells/TraitMgr.cpp | 45 |
1 files changed, 35 insertions, 10 deletions
diff --git a/src/server/game/Spells/TraitMgr.cpp b/src/server/game/Spells/TraitMgr.cpp index 3f0e73c7679..32b8c179545 100644 --- a/src/server/game/Spells/TraitMgr.cpp +++ b/src/server/game/Spells/TraitMgr.cpp @@ -493,21 +493,23 @@ std::vector<UF::TraitEntry> GetGrantedTraitEntriesForConfig(WorldPackets::Traits if (!trees) return entries; - auto getOrCreateEntry = [&entries](int32 nodeId, int32 entryId) + auto addGrantedRankToEntry = [&entries](int32 nodeId, NodeEntry const& entry, int32 grantedRanks) { auto itr = std::ranges::find_if(entries, [&](UF::TraitEntry const& traitEntry) { - return traitEntry.TraitNodeID == nodeId && traitEntry.TraitNodeEntryID == entryId; + return traitEntry.TraitNodeID == nodeId && traitEntry.TraitNodeEntryID == int32(entry.Data->ID); }); if (itr == entries.end()) { itr = entries.emplace(entries.end()); itr->TraitNodeID = nodeId; - itr->TraitNodeEntryID = entryId; + itr->TraitNodeEntryID = int32(entry.Data->ID); itr->Rank = 0; itr->GrantedRanks = 0; } - return &*itr; + itr->GrantedRanks += grantedRanks; + if (itr->GrantedRanks > entry.Data->MaxRanks) + itr->GrantedRanks = entry.Data->MaxRanks; }; Optional<std::map<int32, int32>> cachedCurrencies; @@ -519,18 +521,18 @@ std::vector<UF::TraitEntry> GetGrantedTraitEntriesForConfig(WorldPackets::Traits for (NodeEntry const& entry : node->Entries) for (TraitCondEntry const* condition : entry.Conditions) if (condition->GetCondType() == TraitConditionType::Granted && MeetsTraitCondition(traitConfig, player, condition, cachedCurrencies)) - getOrCreateEntry(node->Data->ID, entry.Data->ID)->GrantedRanks += condition->GrantedRanks; + addGrantedRankToEntry(node->Data->ID, entry, condition->GrantedRanks); for (TraitCondEntry const* condition : node->Conditions) if (condition->GetCondType() == TraitConditionType::Granted && MeetsTraitCondition(traitConfig, player, condition, cachedCurrencies)) for (NodeEntry const& entry : node->Entries) - getOrCreateEntry(node->Data->ID, entry.Data->ID)->GrantedRanks += condition->GrantedRanks; + addGrantedRankToEntry(node->Data->ID, entry, condition->GrantedRanks); for (NodeGroup const* group : node->Groups) for (TraitCondEntry const* condition : group->Conditions) if (condition->GetCondType() == TraitConditionType::Granted && MeetsTraitCondition(traitConfig, player, condition, cachedCurrencies)) for (NodeEntry const& entry : node->Entries) - getOrCreateEntry(node->Data->ID, entry.Data->ID)->GrantedRanks += condition->GrantedRanks; + addGrantedRankToEntry(node->Data->ID, entry, condition->GrantedRanks); } } @@ -553,7 +555,7 @@ bool IsValidEntry(WorldPackets::Traits::TraitEntry const& traitEntry) return true; } -LearnResult ValidateConfig(WorldPackets::Traits::TraitConfig const& traitConfig, PlayerDataAccessor player, bool requireSpendingAllCurrencies /*= false*/) +LearnResult ValidateConfig(WorldPackets::Traits::TraitConfig& traitConfig, PlayerDataAccessor player, bool requireSpendingAllCurrencies /*= false*/, bool removeInvalidEntries /*= false*/) { auto getNodeEntryCount = [&](int32 traitNodeId) { @@ -603,13 +605,13 @@ LearnResult ValidateConfig(WorldPackets::Traits::TraitConfig const& traitConfig, return !hasConditions; }; - for (WorldPackets::Traits::TraitEntry const& traitEntry : traitConfig.Entries) + auto isValidTraitEntry = [&](WorldPackets::Traits::TraitEntry const& traitEntry) { if (!IsValidEntry(traitEntry)) return LearnResult::Unknown; Node const* node = Trinity::Containers::MapGetValuePtr(_traitNodes, traitEntry.TraitNodeID); - if (node->Data->GetType() == TraitNodeType::Selection) + if (node->Data->GetType() == TraitNodeType::Selection || node->Data->GetType() == TraitNodeType::SubTreeSelection) if (getNodeEntryCount(traitEntry.TraitNodeID) != 1) return LearnResult::Unknown; @@ -643,6 +645,29 @@ LearnResult ValidateConfig(WorldPackets::Traits::TraitConfig const& traitConfig, if (!hasAnyParentTrait) return LearnResult::NotEnoughTalentsInPrimaryTree; } + + return LearnResult::Ok; + }; + + for (auto itr = traitConfig.Entries.begin(); itr != traitConfig.Entries.end(); ) + { + LearnResult result = isValidTraitEntry(*itr); + if (result != LearnResult::Ok) + { + if (!removeInvalidEntries) + return result; + + if (!itr->GrantedRanks // fully remove entries that don't have granted ranks + || !itr->Rank) // ... or entries that do have them and don't have any additional spent ranks (can happen if the same entry is revalidated after first removing all spent ranks) + traitConfig.Entries.erase(itr); + else + itr->Rank = 0; + + // revalidate entire config - a removed entry will invalidate all other entries that depend on it + itr = traitConfig.Entries.begin(); + } + else + ++itr; } std::map<int32, int32> grantedCurrencies; |