From 4db686a65264b720df16712b92b4b97eba01892f Mon Sep 17 00:00:00 2001 From: Kelsi Date: Mon, 9 Mar 2026 16:43:33 -0700 Subject: [PATCH] Parse SMSG_PERIODICAURALOG to show DoT/HoT numbers in combat text Previously all periodic aura ticks were silently discarded. Now parses victim/caster GUIDs, auraType, and damage/heal value for the two most common types (PERIODIC_DAMAGE=3 and PERIODIC_HEAL=8) and generates PERIODIC_DAMAGE/PERIODIC_HEAL combat text entries. Falls back safely to consume-all on unknown aura types. --- src/game/game_handler.cpp | 44 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 62621f2a..39c83876 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -3024,7 +3024,49 @@ void GameHandler::handlePacket(network::Packet& packet) { case Opcode::SMSG_SET_PCT_SPELL_MODIFIER: case Opcode::SMSG_SPELL_DELAYED: case Opcode::SMSG_EQUIPMENT_SET_SAVED: - case Opcode::SMSG_PERIODICAURALOG: + case Opcode::SMSG_PERIODICAURALOG: { + // packed_guid victim, packed_guid caster, uint32 spellId, uint32 count, then per-effect + if (packet.getSize() - packet.getReadPos() < 2) break; + uint64_t victimGuid = UpdateObjectParser::readPackedGuid(packet); + if (packet.getSize() - packet.getReadPos() < 2) break; + uint64_t casterGuid = UpdateObjectParser::readPackedGuid(packet); + if (packet.getSize() - packet.getReadPos() < 8) break; + uint32_t spellId = packet.readUInt32(); + uint32_t count = packet.readUInt32(); + bool isPlayerVictim = (victimGuid == playerGuid); + bool isPlayerCaster = (casterGuid == playerGuid); + if (!isPlayerVictim && !isPlayerCaster) { + packet.setReadPos(packet.getSize()); + break; + } + for (uint32_t i = 0; i < count && packet.getSize() - packet.getReadPos() >= 1; ++i) { + uint8_t auraType = packet.readUInt8(); + if (auraType == 3 || auraType == 89) { + // PERIODIC_DAMAGE / PERIODIC_DAMAGE_PERCENT: damage+school+absorbed+resisted + if (packet.getSize() - packet.getReadPos() < 16) break; + uint32_t dmg = packet.readUInt32(); + /*uint32_t school=*/ packet.readUInt32(); + /*uint32_t abs=*/ packet.readUInt32(); + /*uint32_t res=*/ packet.readUInt32(); + addCombatText(CombatTextEntry::PERIODIC_DAMAGE, static_cast(dmg), + spellId, isPlayerCaster); + } else if (auraType == 8 || auraType == 124 || auraType == 45) { + // PERIODIC_HEAL / PERIODIC_HEAL_PCT / OBS_MOD_HEALTH: heal+maxHeal+overHeal + if (packet.getSize() - packet.getReadPos() < 12) break; + uint32_t heal = packet.readUInt32(); + /*uint32_t max=*/ packet.readUInt32(); + /*uint32_t over=*/ packet.readUInt32(); + addCombatText(CombatTextEntry::PERIODIC_HEAL, static_cast(heal), + spellId, isPlayerCaster); + } else { + // Unknown/untracked aura type — stop parsing this event safely + packet.setReadPos(packet.getSize()); + break; + } + } + packet.setReadPos(packet.getSize()); + break; + } case Opcode::SMSG_SPELLENERGIZELOG: case Opcode::SMSG_ENVIRONMENTAL_DAMAGE_LOG: case Opcode::SMSG_SET_PROFICIENCY: