Fix/talent tree ordered map (#2222)

Fixes #2050

InitTalents builds a map of talentRow → [TalentEntry*] and iterates it
to teach talents row by row. WoW's talent system requires each row to be
filled before unlocking the next, so iteration must happen in ascending
row order. Commit
b474dc4 ("Performance optim") changed the container from std::map to
std::unordered_map, which has no guaranteed key ordering. As a result,
bots would frequently attempt to learn talents in a row whose
prerequisites hadn't been met
  yet, silently skipping them. I belive it's the reason of #2050 issue.

The fix is a one-character type change: restoring std::map<uint32, ...>,
which guarantees ascending key (row) order.

  How to Test the Changes

   1. Make fresh installation
   2. Create new character
   3. Observe talents tree of fresh rnd bots
  

  Was AI assistance used while working on this change?

- [X] Yes — GitHub Copilot CLI was used to identify the root cause
(unordered_map introduced in b474dc4 breaking talent row ordering),
stage the one-line fix, and draft this PR description. The code change
was reviewed and fully
  understood before submission.

Root cause commit: b474dc44bb6323430a84fc17c1ec046f9919a101
("Performance optim") — changed std::map to std::unordered_map in
InitTalents, breaking the row-ordering guarantee that WoW's talent
prerequisite system depends on.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
oskov 2026-03-20 21:42:07 +02:00 committed by GitHub
parent d5762b7e0f
commit f160420d70
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -762,7 +762,7 @@ void PlayerbotFactory::InitPetTalents()
// pet_family->petTalentType); // pet_family->petTalentType);
return; return;
} }
std::unordered_map<uint32, std::vector<TalentEntry const*>> spells; std::map<uint32, std::vector<TalentEntry const*>> spells;
bool diveTypePet = (1LL << ci->family) & diveMask; bool diveTypePet = (1LL << ci->family) & diveMask;
for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i) for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i)
@ -2653,7 +2653,7 @@ void PlayerbotFactory::InitSpecialSpells()
void PlayerbotFactory::InitTalents(uint32 specNo) void PlayerbotFactory::InitTalents(uint32 specNo)
{ {
uint32 classMask = bot->getClassMask(); uint32 classMask = bot->getClassMask();
std::unordered_map<uint32, std::vector<TalentEntry const*>> spells; std::map<uint32, std::vector<TalentEntry const*>> spells;
for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i) for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i)
{ {
TalentEntry const* talentInfo = sTalentStore.LookupEntry(i); TalentEntry const* talentInfo = sTalentStore.LookupEntry(i);