mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-24 16:10:14 +00:00
Fix TBC item query parser: add TBC-specific parseItemQueryResponse override
TBC 2.4.3 SMSG_ITEM_QUERY_SINGLE_RESPONSE differs from WotLK: no Flags2, no BuyCount, statsCount-many stat pairs (not always 10), and no ScalingStatDistribution/ScalingStatValue. Without this override, TbcPacketParsers fell back to the WotLK parser and misread stats/armor with a cascading 16-byte offset. Classic (Vanilla) was already safe via its own independent ClassicPacketParsers::parseItemQueryResponse().
This commit is contained in:
parent
764f2b8edc
commit
28b4a3a599
2 changed files with 109 additions and 0 deletions
|
|
@ -278,6 +278,7 @@ public:
|
|||
bool parseCharEnum(network::Packet& packet, CharEnumResponse& response) override;
|
||||
bool parseAuraUpdate(network::Packet& packet, AuraUpdateData& data, bool isAll = false) override;
|
||||
bool parseNameQueryResponse(network::Packet& packet, NameQueryResponseData& data) override;
|
||||
bool parseItemQueryResponse(network::Packet& packet, ItemQueryResponseData& data) override;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -533,5 +533,113 @@ bool TbcPacketParsers::parseNameQueryResponse(network::Packet& packet, NameQuery
|
|||
return false;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// TBC parseItemQueryResponse - SMSG_ITEM_QUERY_SINGLE_RESPONSE (2.4.3 format)
|
||||
//
|
||||
// Differences from WotLK (handled by base class ItemQueryResponseParser::parse):
|
||||
// - No Flags2 field (WotLK added a second flags uint32 after Flags)
|
||||
// - No BuyCount field (WotLK added this between Flags2 and BuyPrice)
|
||||
// - Stats: sends exactly statsCount pairs (WotLK always sends 10)
|
||||
// - No ScalingStatDistribution / ScalingStatValue (WotLK-only heirloom scaling)
|
||||
//
|
||||
// Differences from Classic (ClassicPacketParsers::parseItemQueryResponse):
|
||||
// - Has SoundOverrideSubclass (int32) after subClass (Classic lacks it)
|
||||
// - Has statsCount prefix (Classic reads 10 pairs with no prefix)
|
||||
// ============================================================================
|
||||
bool TbcPacketParsers::parseItemQueryResponse(network::Packet& packet, ItemQueryResponseData& data) {
|
||||
data.entry = packet.readUInt32();
|
||||
if (data.entry & 0x80000000) {
|
||||
data.entry &= ~0x80000000;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t itemClass = packet.readUInt32();
|
||||
uint32_t subClass = packet.readUInt32();
|
||||
data.itemClass = itemClass;
|
||||
data.subClass = subClass;
|
||||
packet.readUInt32(); // SoundOverrideSubclass (int32, -1 = no override)
|
||||
data.subclassName = "";
|
||||
|
||||
// Name strings
|
||||
data.name = packet.readString();
|
||||
packet.readString(); // name2
|
||||
packet.readString(); // name3
|
||||
packet.readString(); // name4
|
||||
|
||||
data.displayInfoId = packet.readUInt32();
|
||||
data.quality = packet.readUInt32();
|
||||
|
||||
packet.readUInt32(); // Flags (TBC: 1 flags field only — no Flags2)
|
||||
// TBC: NO Flags2, NO BuyCount
|
||||
packet.readUInt32(); // BuyPrice
|
||||
data.sellPrice = packet.readUInt32();
|
||||
|
||||
data.inventoryType = packet.readUInt32();
|
||||
|
||||
packet.readUInt32(); // AllowableClass
|
||||
packet.readUInt32(); // AllowableRace
|
||||
packet.readUInt32(); // ItemLevel
|
||||
packet.readUInt32(); // RequiredLevel
|
||||
packet.readUInt32(); // RequiredSkill
|
||||
packet.readUInt32(); // RequiredSkillRank
|
||||
packet.readUInt32(); // RequiredSpell
|
||||
packet.readUInt32(); // RequiredHonorRank
|
||||
packet.readUInt32(); // RequiredCityRank
|
||||
packet.readUInt32(); // RequiredReputationFaction
|
||||
packet.readUInt32(); // RequiredReputationRank
|
||||
packet.readUInt32(); // MaxCount
|
||||
data.maxStack = static_cast<int32_t>(packet.readUInt32()); // Stackable
|
||||
data.containerSlots = packet.readUInt32();
|
||||
|
||||
// TBC: statsCount prefix + exactly statsCount pairs (WotLK always sends 10)
|
||||
uint32_t statsCount = packet.readUInt32();
|
||||
if (statsCount > 10) statsCount = 10; // sanity cap
|
||||
for (uint32_t i = 0; i < statsCount; i++) {
|
||||
uint32_t statType = packet.readUInt32();
|
||||
int32_t statValue = static_cast<int32_t>(packet.readUInt32());
|
||||
switch (statType) {
|
||||
case 3: data.agility = statValue; break;
|
||||
case 4: data.strength = statValue; break;
|
||||
case 5: data.intellect = statValue; break;
|
||||
case 6: data.spirit = statValue; break;
|
||||
case 7: data.stamina = statValue; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
// TBC: NO ScalingStatDistribution, NO ScalingStatValue (WotLK-only)
|
||||
|
||||
// 5 damage entries
|
||||
bool haveWeaponDamage = false;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
float dmgMin = packet.readFloat();
|
||||
float dmgMax = packet.readFloat();
|
||||
uint32_t damageType = packet.readUInt32();
|
||||
if (!haveWeaponDamage && dmgMax > 0.0f) {
|
||||
if (damageType == 0 || data.damageMax <= 0.0f) {
|
||||
data.damageMin = dmgMin;
|
||||
data.damageMax = dmgMax;
|
||||
haveWeaponDamage = (damageType == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data.armor = static_cast<int32_t>(packet.readUInt32());
|
||||
|
||||
if (packet.getSize() - packet.getReadPos() >= 28) {
|
||||
packet.readUInt32(); // HolyRes
|
||||
packet.readUInt32(); // FireRes
|
||||
packet.readUInt32(); // NatureRes
|
||||
packet.readUInt32(); // FrostRes
|
||||
packet.readUInt32(); // ShadowRes
|
||||
packet.readUInt32(); // ArcaneRes
|
||||
data.delayMs = packet.readUInt32();
|
||||
}
|
||||
|
||||
data.valid = !data.name.empty();
|
||||
LOG_DEBUG("[TBC] Item query: ", data.name, " quality=", data.quality,
|
||||
" invType=", data.inventoryType, " armor=", data.armor);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace game
|
||||
} // namespace wowee
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue