mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-23 07:40:14 +00:00
Fix trainer system and add critical spell/quest opcodes
Trainer System Fixes: - Fix CMSG_TRAINER_BUY_SPELL packet: remove incorrect trainerType field (12 bytes not 16) - Correct spell state interpretation: 0=available, 1=unavailable, 2=known - Add dynamic prerequisite re-evaluation in real-time as spells are learned - Immediately update knownSpells on SMSG_TRAINER_BUY_SUCCEEDED - Add "Show unavailable spells" checkbox filter to trainer window - Override server state when prerequisites become met client-side New Spell Opcodes: - SMSG_SUPERCEDED_SPELL (0x12C): handle spell rank upgrades - SMSG_SEND_UNLEARN_SPELLS (0x41F): handle bulk unlearning (respec/dual-spec) - CMSG_TRAINER_LIST (0x1B0): trainer request opcode Quest System: - SMSG_QUESTUPDATE_COMPLETE (0x195): mark quests complete when objectives done - Show "Quest Complete" message and enable turn-in UI Detailed logging: - SMSG_INITIAL_SPELLS now logs packet size and first 10 spell IDs - Money values logged during trainer purchases - Trainer spell states and prerequisites logged for debugging This enables proper spell progression chains, spec changes, and quest completion notifications matching retail WoW 3.3.5a behavior.
This commit is contained in:
parent
8af895c025
commit
a764eea2ec
6 changed files with 632 additions and 36 deletions
|
|
@ -829,6 +829,8 @@ bool UpdateObjectParser::parseMovementBlock(network::Packet& packet, UpdateBlock
|
|||
}
|
||||
|
||||
bool UpdateObjectParser::parseUpdateFields(network::Packet& packet, UpdateBlock& block) {
|
||||
size_t startPos = packet.getReadPos();
|
||||
|
||||
// Read number of blocks (each block is 32 fields = 32 bits)
|
||||
uint8_t blockCount = packet.readUInt8();
|
||||
|
||||
|
|
@ -836,7 +838,10 @@ bool UpdateObjectParser::parseUpdateFields(network::Packet& packet, UpdateBlock&
|
|||
return true; // No fields to update
|
||||
}
|
||||
|
||||
LOG_DEBUG(" Parsing ", (int)blockCount, " field blocks");
|
||||
uint32_t fieldsCapacity = blockCount * 32;
|
||||
LOG_INFO(" UPDATE MASK PARSE:");
|
||||
LOG_INFO(" maskBlockCount = ", (int)blockCount);
|
||||
LOG_INFO(" fieldsCapacity (blocks * 32) = ", fieldsCapacity);
|
||||
|
||||
// Read update mask
|
||||
std::vector<uint32_t> updateMask(blockCount);
|
||||
|
|
@ -844,6 +849,10 @@ bool UpdateObjectParser::parseUpdateFields(network::Packet& packet, UpdateBlock&
|
|||
updateMask[i] = packet.readUInt32();
|
||||
}
|
||||
|
||||
// Find highest set bit
|
||||
uint16_t highestSetBit = 0;
|
||||
uint32_t valuesReadCount = 0;
|
||||
|
||||
// Read field values for each bit set in mask
|
||||
for (int blockIdx = 0; blockIdx < blockCount; ++blockIdx) {
|
||||
uint32_t mask = updateMask[blockIdx];
|
||||
|
|
@ -851,15 +860,27 @@ bool UpdateObjectParser::parseUpdateFields(network::Packet& packet, UpdateBlock&
|
|||
for (int bit = 0; bit < 32; ++bit) {
|
||||
if (mask & (1 << bit)) {
|
||||
uint16_t fieldIndex = blockIdx * 32 + bit;
|
||||
if (fieldIndex > highestSetBit) {
|
||||
highestSetBit = fieldIndex;
|
||||
}
|
||||
uint32_t value = packet.readUInt32();
|
||||
block.fields[fieldIndex] = value;
|
||||
valuesReadCount++;
|
||||
|
||||
LOG_DEBUG(" Field[", fieldIndex, "] = 0x", std::hex, value, std::dec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOG_DEBUG(" Parsed ", block.fields.size(), " fields");
|
||||
size_t endPos = packet.getReadPos();
|
||||
size_t bytesUsed = endPos - startPos;
|
||||
size_t bytesRemaining = packet.getSize() - endPos;
|
||||
|
||||
LOG_INFO(" highestSetBitIndex = ", highestSetBit);
|
||||
LOG_INFO(" valuesReadCount = ", valuesReadCount);
|
||||
LOG_INFO(" bytesUsedForFields = ", bytesUsed);
|
||||
LOG_INFO(" bytesRemainingInPacket = ", bytesRemaining);
|
||||
LOG_INFO(" Parsed ", block.fields.size(), " fields");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -932,6 +953,10 @@ bool UpdateObjectParser::parse(network::Packet& packet, UpdateObjectData& data)
|
|||
// Read block count
|
||||
data.blockCount = packet.readUInt32();
|
||||
|
||||
LOG_INFO("SMSG_UPDATE_OBJECT:");
|
||||
LOG_INFO(" objectCount = ", data.blockCount);
|
||||
LOG_INFO(" packetSize = ", packet.getSize());
|
||||
|
||||
// Check for out-of-range objects first
|
||||
if (packet.getReadPos() + 1 <= packet.getSize()) {
|
||||
uint8_t firstByte = packet.readUInt8();
|
||||
|
|
@ -1973,9 +1998,12 @@ bool XpGainParser::parse(network::Packet& packet, XpGainData& data) {
|
|||
// ============================================================
|
||||
|
||||
bool InitialSpellsParser::parse(network::Packet& packet, InitialSpellsData& data) {
|
||||
size_t packetSize = packet.getSize();
|
||||
data.talentSpec = packet.readUInt8();
|
||||
uint16_t spellCount = packet.readUInt16();
|
||||
|
||||
LOG_INFO("SMSG_INITIAL_SPELLS: packetSize=", packetSize, " bytes, spellCount=", spellCount);
|
||||
|
||||
data.spellIds.reserve(spellCount);
|
||||
for (uint16_t i = 0; i < spellCount; ++i) {
|
||||
uint32_t spellId = packet.readUInt32();
|
||||
|
|
@ -1997,8 +2025,19 @@ bool InitialSpellsParser::parse(network::Packet& packet, InitialSpellsData& data
|
|||
data.cooldowns.push_back(entry);
|
||||
}
|
||||
|
||||
LOG_INFO("Initial spells: ", data.spellIds.size(), " spells, ",
|
||||
LOG_INFO("Initial spells parsed: ", data.spellIds.size(), " spells, ",
|
||||
data.cooldowns.size(), " cooldowns");
|
||||
|
||||
// Log first 10 spell IDs for debugging
|
||||
if (!data.spellIds.empty()) {
|
||||
std::string first10;
|
||||
for (size_t i = 0; i < std::min(size_t(10), data.spellIds.size()); ++i) {
|
||||
if (!first10.empty()) first10 += ", ";
|
||||
first10 += std::to_string(data.spellIds[i]);
|
||||
}
|
||||
LOG_INFO("First spells: ", first10);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -2682,10 +2721,9 @@ bool TrainerListParser::parse(network::Packet& packet, TrainerListData& data) {
|
|||
return true;
|
||||
}
|
||||
|
||||
network::Packet TrainerBuySpellPacket::build(uint64_t trainerGuid, uint32_t trainerId, uint32_t spellId) {
|
||||
network::Packet TrainerBuySpellPacket::build(uint64_t trainerGuid, uint32_t spellId) {
|
||||
network::Packet packet(static_cast<uint16_t>(Opcode::CMSG_TRAINER_BUY_SPELL));
|
||||
packet.writeUInt64(trainerGuid);
|
||||
packet.writeUInt32(trainerId);
|
||||
packet.writeUInt32(spellId);
|
||||
return packet;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue