mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-26 21:13:51 +00:00
fix: rewrite handleTalentsInfo with correct WotLK SMSG_TALENTS_INFO packet format
TalentsInfoParser used a completely wrong byte layout (expected big-endian counts, wrong field order), causing unspentTalentPoints to always be misread. This made canLearn always false so clicking talents did nothing. New format matches the actual WoW 3.3.5a wire format: uint8 talentType, uint32 unspentTalents, uint8 groupCount, uint8 activeGroup, per-group: uint8 talentCount, [uint32 id + uint8 rank]×N, uint8 glyphCount, [uint16]×M Matches the proven parsing logic in handleInspectResults.
This commit is contained in:
parent
e4fd4b4e6d
commit
d3159791de
1 changed files with 51 additions and 28 deletions
|
|
@ -16435,44 +16435,67 @@ void GameHandler::handleUnlearnSpells(network::Packet& packet) {
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
void GameHandler::handleTalentsInfo(network::Packet& packet) {
|
void GameHandler::handleTalentsInfo(network::Packet& packet) {
|
||||||
TalentsInfoData data;
|
// SMSG_TALENTS_INFO (WotLK 3.3.5a) correct wire format:
|
||||||
if (!TalentsInfoParser::parse(packet, data)) return;
|
// uint8 talentType (0 = own talents, 1 = inspect result — own talent packets always 0)
|
||||||
|
// uint32 unspentTalents
|
||||||
|
// uint8 talentGroupCount
|
||||||
|
// uint8 activeTalentGroup
|
||||||
|
// Per group: uint8 talentCount, [uint32 talentId + uint8 rank] × count,
|
||||||
|
// uint8 glyphCount, [uint16 glyphId] × count
|
||||||
|
|
||||||
|
if (packet.getSize() - packet.getReadPos() < 1) return;
|
||||||
|
uint8_t talentType = packet.readUInt8();
|
||||||
|
if (talentType != 0) {
|
||||||
|
// type 1 = inspect result; handled by handleInspectResults — ignore here
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (packet.getSize() - packet.getReadPos() < 6) {
|
||||||
|
LOG_WARNING("handleTalentsInfo: packet too short for header");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t unspentTalents = packet.readUInt32();
|
||||||
|
uint8_t talentGroupCount = packet.readUInt8();
|
||||||
|
uint8_t activeTalentGroup = packet.readUInt8();
|
||||||
|
if (activeTalentGroup > 1) activeTalentGroup = 0;
|
||||||
|
|
||||||
// Ensure talent DBCs are loaded
|
// Ensure talent DBCs are loaded
|
||||||
loadTalentDbc();
|
loadTalentDbc();
|
||||||
|
|
||||||
// Validate spec number
|
activeTalentSpec_ = activeTalentGroup;
|
||||||
if (data.talentSpec > 1) {
|
|
||||||
LOG_WARNING("Invalid talent spec: ", (int)data.talentSpec);
|
for (uint8_t g = 0; g < talentGroupCount && g < 2; ++g) {
|
||||||
return;
|
if (packet.getSize() - packet.getReadPos() < 1) break;
|
||||||
|
uint8_t talentCount = packet.readUInt8();
|
||||||
|
learnedTalents_[g].clear();
|
||||||
|
for (uint8_t t = 0; t < talentCount; ++t) {
|
||||||
|
if (packet.getSize() - packet.getReadPos() < 5) break;
|
||||||
|
uint32_t talentId = packet.readUInt32();
|
||||||
|
uint8_t rank = packet.readUInt8();
|
||||||
|
learnedTalents_[g][talentId] = rank;
|
||||||
|
}
|
||||||
|
learnedGlyphs_[g].fill(0);
|
||||||
|
if (packet.getSize() - packet.getReadPos() < 1) break;
|
||||||
|
uint8_t glyphCount = packet.readUInt8();
|
||||||
|
for (uint8_t gl = 0; gl < glyphCount; ++gl) {
|
||||||
|
if (packet.getSize() - packet.getReadPos() < 2) break;
|
||||||
|
uint16_t glyphId = packet.readUInt16();
|
||||||
|
if (gl < MAX_GLYPH_SLOTS) learnedGlyphs_[g][gl] = glyphId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store talents for this spec
|
unspentTalentPoints_[activeTalentGroup] =
|
||||||
unspentTalentPoints_[data.talentSpec] = data.unspentPoints;
|
static_cast<uint8_t>(unspentTalents > 255 ? 255 : unspentTalents);
|
||||||
|
|
||||||
// Clear and rebuild learned talents map for this spec
|
LOG_INFO("handleTalentsInfo: unspent=", unspentTalents,
|
||||||
// Note: If a talent appears in the packet, it's learned (ranks are 0-indexed)
|
" groups=", (int)talentGroupCount, " active=", (int)activeTalentGroup,
|
||||||
learnedTalents_[data.talentSpec].clear();
|
" learned=", learnedTalents_[activeTalentGroup].size());
|
||||||
for (const auto& talent : data.talents) {
|
|
||||||
learnedTalents_[data.talentSpec][talent.talentId] = talent.currentRank;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_INFO("Talents loaded: spec=", (int)data.talentSpec,
|
|
||||||
" unspent=", (int)unspentTalentPoints_[data.talentSpec],
|
|
||||||
" learned=", learnedTalents_[data.talentSpec].size());
|
|
||||||
|
|
||||||
// If this is the first spec received after login, set it as the active spec
|
|
||||||
if (!talentsInitialized_) {
|
if (!talentsInitialized_) {
|
||||||
talentsInitialized_ = true;
|
talentsInitialized_ = true;
|
||||||
activeTalentSpec_ = data.talentSpec;
|
if (unspentTalents > 0) {
|
||||||
|
addSystemChatMessage("You have " + std::to_string(unspentTalents)
|
||||||
// Show message to player about active spec
|
+ " unspent talent point" + (unspentTalents != 1 ? "s" : "") + ".");
|
||||||
if (unspentTalentPoints_[data.talentSpec] > 0) {
|
|
||||||
std::string msg = "You have " + std::to_string(unspentTalentPoints_[data.talentSpec]) +
|
|
||||||
" unspent talent point";
|
|
||||||
if (unspentTalentPoints_[data.talentSpec] > 1) msg += "s";
|
|
||||||
msg += " in spec " + std::to_string(data.talentSpec + 1);
|
|
||||||
addSystemChatMessage(msg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue