fix: R key resets camera angles only; consume all SpellCastTargets bytes

- CameraController::resetAngles(): new method that only resets yaw/pitch
  without teleporting the player. R key now calls resetAngles() instead
  of reset() so pressing R no longer moves the character to spawn.
  The full reset() (position + angles) is still used on world-entry and
  respawn via application.cpp.

- packet_parsers_classic: parseSpellStart now calls
  skipClassicSpellCastTargets() to consume all target payload bytes
  (UNIT, ITEM, SOURCE_LOCATION, DEST_LOCATION, etc.) instead of only
  handling UNIT/OBJECT. Prevents packet-read corruption for ground-
  targeted AoE spells.

- packet_parsers_tbc: added skipTbcSpellCastTargets() static helper
  (uint32 targetFlags, full payload coverage including TRADE_ITEM and
  STRING targets). parseSpellStart now uses it.
This commit is contained in:
Kelsi 2026-03-17 21:52:45 -07:00
parent a731223e47
commit 32497552d1
4 changed files with 95 additions and 33 deletions

View file

@ -520,23 +520,20 @@ bool ClassicPacketParsers::parseSpellStart(network::Packet& packet, SpellStartDa
data.castFlags = packet.readUInt16(); // uint16 in Vanilla (uint32 in TBC/WotLK)
data.castTime = packet.readUInt32();
// SpellCastTargets: uint16 targetFlags in Vanilla (uint32 in TBC/WotLK)
if (rem() < 2) {
LOG_WARNING("[Classic] Spell start: missing targetFlags");
packet.setReadPos(startPos);
return false;
}
uint16_t targetFlags = packet.readUInt16();
// TARGET_FLAG_UNIT (0x02) or TARGET_FLAG_OBJECT (0x800) carry a packed GUID
if ((targetFlags & 0x02) || (targetFlags & 0x800)) {
if (!hasFullPackedGuid(packet)) {
packet.setReadPos(startPos);
return false;
}
data.targetGuid = UpdateObjectParser::readPackedGuid(packet);
// SpellCastTargets: consume ALL target payload types so subsequent reads stay aligned.
// Previously only UNIT(0x02)/OBJECT(0x800) were handled; DEST_LOCATION(0x40),
// SOURCE_LOCATION(0x20), and ITEM(0x10) bytes were silently skipped, corrupting
// castFlags/castTime for every AOE/ground-targeted spell (Rain of Fire, Blizzard, etc.).
{
uint64_t targetGuid = 0;
// skipClassicSpellCastTargets reads uint16 targetFlags and all payloads.
// Non-fatal on truncation: self-cast spells have zero-byte targets.
skipClassicSpellCastTargets(packet, &targetGuid);
data.targetGuid = targetGuid;
}
LOG_DEBUG("[Classic] Spell start: spell=", data.spellId, " castTime=", data.castTime, "ms");
LOG_DEBUG("[Classic] Spell start: spell=", data.spellId, " castTime=", data.castTime, "ms",
" targetGuid=0x", std::hex, data.targetGuid, std::dec);
return true;
}