diff --git a/Data/expansions/turtle/opcodes.json b/Data/expansions/turtle/opcodes.json index 9e40fbf7..da0efa4e 100644 --- a/Data/expansions/turtle/opcodes.json +++ b/Data/expansions/turtle/opcodes.json @@ -38,6 +38,11 @@ "SMSG_UPDATE_OBJECT": "0x0A9", "SMSG_COMPRESSED_UPDATE_OBJECT": "0x1F6", "SMSG_MONSTER_MOVE_TRANSPORT": "0x2AE", + "SMSG_SPLINE_MOVE_SET_WALK_MODE": "0x30D", + "SMSG_SPLINE_MOVE_SET_RUN_MODE": "0x30E", + "SMSG_SPLINE_MOVE_SET_RUN_SPEED": "0x2FE", + "SMSG_SPLINE_MOVE_SET_RUN_BACK_SPEED": "0x2FF", + "SMSG_SPLINE_MOVE_SET_SWIM_SPEED": "0x300", "SMSG_DESTROY_OBJECT": "0x0AA", "CMSG_MESSAGECHAT": "0x095", "SMSG_MESSAGECHAT": "0x096", @@ -103,7 +108,9 @@ "SMSG_ATTACKSTART": "0x143", "SMSG_ATTACKSTOP": "0x144", "SMSG_ATTACKERSTATEUPDATE": "0x14A", + "SMSG_AI_REACTION": "0x13C", "SMSG_SPELLNONMELEEDAMAGELOG": "0x250", + "SMSG_PLAY_SPELL_VISUAL": "0x1F3", "SMSG_SPELLHEALLOG": "0x150", "SMSG_SPELLENERGIZELOG": "0x151", "SMSG_PERIODICAURALOG": "0x24E", diff --git a/include/game/opcode_table.hpp b/include/game/opcode_table.hpp index b4a4466c..ab953e46 100644 --- a/include/game/opcode_table.hpp +++ b/include/game/opcode_table.hpp @@ -65,6 +65,11 @@ enum class LogicalOpcode : uint16_t { SMSG_UPDATE_OBJECT, SMSG_COMPRESSED_UPDATE_OBJECT, SMSG_MONSTER_MOVE_TRANSPORT, + SMSG_SPLINE_MOVE_SET_WALK_MODE, + SMSG_SPLINE_MOVE_SET_RUN_MODE, + SMSG_SPLINE_MOVE_SET_RUN_SPEED, + SMSG_SPLINE_MOVE_SET_RUN_BACK_SPEED, + SMSG_SPLINE_MOVE_SET_SWIM_SPEED, SMSG_DESTROY_OBJECT, // ---- Chat ---- @@ -168,7 +173,9 @@ enum class LogicalOpcode : uint16_t { SMSG_ATTACKSTART, SMSG_ATTACKSTOP, SMSG_ATTACKERSTATEUPDATE, + SMSG_AI_REACTION, SMSG_SPELLNONMELEEDAMAGELOG, + SMSG_PLAY_SPELL_VISUAL, SMSG_SPELLHEALLOG, SMSG_SPELLENERGIZELOG, SMSG_PERIODICAURALOG, diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 75e9c3b9..b54efd0f 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -934,6 +934,17 @@ void GameHandler::handlePacket(network::Packet& packet) { handleTextEmote(packet); } break; + case Opcode::SMSG_EMOTE: { + if (state != WorldState::IN_WORLD) break; + // SMSG_EMOTE: uint32 emoteAnim, uint64 sourceGuid + if (packet.getSize() - packet.getReadPos() < 12) break; + uint32_t emoteAnim = packet.readUInt32(); + uint64_t sourceGuid = packet.readUInt64(); + if (emoteAnimCallback_ && sourceGuid != 0) { + emoteAnimCallback_(sourceGuid, emoteAnim); + } + break; + } case Opcode::SMSG_CHANNEL_NOTIFY: // Accept during ENTERING_WORLD too — server auto-joins channels before VERIFY_WORLD @@ -1032,6 +1043,28 @@ void GameHandler::handlePacket(network::Packet& packet) { case Opcode::SMSG_MONSTER_MOVE_TRANSPORT: handleMonsterMoveTransport(packet); break; + case Opcode::SMSG_SPLINE_MOVE_SET_WALK_MODE: + case Opcode::SMSG_SPLINE_MOVE_SET_RUN_MODE: { + // Minimal parse: PackedGuid + if (packet.getSize() - packet.getReadPos() >= 1) { + (void)UpdateObjectParser::readPackedGuid(packet); + } + break; + } + case Opcode::SMSG_SPLINE_MOVE_SET_RUN_SPEED: + case Opcode::SMSG_SPLINE_MOVE_SET_RUN_BACK_SPEED: + case Opcode::SMSG_SPLINE_MOVE_SET_SWIM_SPEED: { + // Minimal parse: PackedGuid + float speed + if (packet.getSize() - packet.getReadPos() < 5) break; + uint64_t guid = UpdateObjectParser::readPackedGuid(packet); + if (packet.getSize() - packet.getReadPos() < 4) break; + float speed = packet.readFloat(); + if (guid == playerGuid && std::isfinite(speed) && speed > 0.1f && speed < 100.0f && + *logicalOp == Opcode::SMSG_SPLINE_MOVE_SET_RUN_SPEED) { + serverRunSpeed_ = speed; + } + break; + } // ---- Speed Changes ---- case Opcode::SMSG_FORCE_RUN_SPEED_CHANGE: @@ -1094,9 +1127,30 @@ void GameHandler::handlePacket(network::Packet& packet) { case Opcode::SMSG_ATTACKERSTATEUPDATE: handleAttackerStateUpdate(packet); break; + case Opcode::SMSG_AI_REACTION: { + // SMSG_AI_REACTION: uint64 guid, uint32 reaction + if (packet.getSize() - packet.getReadPos() < 12) break; + uint64_t guid = packet.readUInt64(); + uint32_t reaction = packet.readUInt32(); + // Reaction 2 commonly indicates aggro. + if (reaction == 2 && npcAggroCallback_) { + auto entity = entityManager.getEntity(guid); + if (entity) { + npcAggroCallback_(guid, glm::vec3(entity->getX(), entity->getY(), entity->getZ())); + } + } + break; + } case Opcode::SMSG_SPELLNONMELEEDAMAGELOG: handleSpellDamageLog(packet); break; + case Opcode::SMSG_PLAY_SPELL_VISUAL: { + // Minimal parse: uint64 casterGuid, uint32 visualId + if (packet.getSize() - packet.getReadPos() < 12) break; + packet.readUInt64(); + packet.readUInt32(); + break; + } case Opcode::SMSG_SPELLHEALLOG: handleSpellHealLog(packet); break; diff --git a/src/game/opcode_table.cpp b/src/game/opcode_table.cpp index ec480124..a7024d12 100644 --- a/src/game/opcode_table.cpp +++ b/src/game/opcode_table.cpp @@ -64,6 +64,11 @@ static const OpcodeNameEntry kOpcodeNames[] = { {"SMSG_UPDATE_OBJECT", LogicalOpcode::SMSG_UPDATE_OBJECT}, {"SMSG_COMPRESSED_UPDATE_OBJECT", LogicalOpcode::SMSG_COMPRESSED_UPDATE_OBJECT}, {"SMSG_MONSTER_MOVE_TRANSPORT", LogicalOpcode::SMSG_MONSTER_MOVE_TRANSPORT}, + {"SMSG_SPLINE_MOVE_SET_WALK_MODE", LogicalOpcode::SMSG_SPLINE_MOVE_SET_WALK_MODE}, + {"SMSG_SPLINE_MOVE_SET_RUN_MODE", LogicalOpcode::SMSG_SPLINE_MOVE_SET_RUN_MODE}, + {"SMSG_SPLINE_MOVE_SET_RUN_SPEED", LogicalOpcode::SMSG_SPLINE_MOVE_SET_RUN_SPEED}, + {"SMSG_SPLINE_MOVE_SET_RUN_BACK_SPEED", LogicalOpcode::SMSG_SPLINE_MOVE_SET_RUN_BACK_SPEED}, + {"SMSG_SPLINE_MOVE_SET_SWIM_SPEED", LogicalOpcode::SMSG_SPLINE_MOVE_SET_SWIM_SPEED}, {"SMSG_DESTROY_OBJECT", LogicalOpcode::SMSG_DESTROY_OBJECT}, {"CMSG_MESSAGECHAT", LogicalOpcode::CMSG_MESSAGECHAT}, {"SMSG_MESSAGECHAT", LogicalOpcode::SMSG_MESSAGECHAT}, @@ -135,7 +140,9 @@ static const OpcodeNameEntry kOpcodeNames[] = { {"SMSG_ATTACKSTART", LogicalOpcode::SMSG_ATTACKSTART}, {"SMSG_ATTACKSTOP", LogicalOpcode::SMSG_ATTACKSTOP}, {"SMSG_ATTACKERSTATEUPDATE", LogicalOpcode::SMSG_ATTACKERSTATEUPDATE}, + {"SMSG_AI_REACTION", LogicalOpcode::SMSG_AI_REACTION}, {"SMSG_SPELLNONMELEEDAMAGELOG", LogicalOpcode::SMSG_SPELLNONMELEEDAMAGELOG}, + {"SMSG_PLAY_SPELL_VISUAL", LogicalOpcode::SMSG_PLAY_SPELL_VISUAL}, {"SMSG_SPELLHEALLOG", LogicalOpcode::SMSG_SPELLHEALLOG}, {"SMSG_SPELLENERGIZELOG", LogicalOpcode::SMSG_SPELLENERGIZELOG}, {"SMSG_PERIODICAURALOG", LogicalOpcode::SMSG_PERIODICAURALOG}, @@ -418,6 +425,11 @@ void OpcodeTable::loadWotlkDefaults() { {LogicalOpcode::SMSG_UPDATE_OBJECT, 0x0A9}, {LogicalOpcode::SMSG_COMPRESSED_UPDATE_OBJECT, 0x1F6}, {LogicalOpcode::SMSG_MONSTER_MOVE_TRANSPORT, 0x2AE}, + {LogicalOpcode::SMSG_SPLINE_MOVE_SET_WALK_MODE, 0x30D}, + {LogicalOpcode::SMSG_SPLINE_MOVE_SET_RUN_MODE, 0x30E}, + {LogicalOpcode::SMSG_SPLINE_MOVE_SET_RUN_SPEED, 0x2FE}, + {LogicalOpcode::SMSG_SPLINE_MOVE_SET_RUN_BACK_SPEED, 0x2FF}, + {LogicalOpcode::SMSG_SPLINE_MOVE_SET_SWIM_SPEED, 0x300}, {LogicalOpcode::SMSG_DESTROY_OBJECT, 0x0AA}, {LogicalOpcode::CMSG_MESSAGECHAT, 0x095}, {LogicalOpcode::SMSG_MESSAGECHAT, 0x096}, @@ -488,7 +500,9 @@ void OpcodeTable::loadWotlkDefaults() { {LogicalOpcode::SMSG_ATTACKSTART, 0x143}, {LogicalOpcode::SMSG_ATTACKSTOP, 0x144}, {LogicalOpcode::SMSG_ATTACKERSTATEUPDATE, 0x14A}, + {LogicalOpcode::SMSG_AI_REACTION, 0x13C}, {LogicalOpcode::SMSG_SPELLNONMELEEDAMAGELOG, 0x250}, + {LogicalOpcode::SMSG_PLAY_SPELL_VISUAL, 0x1F3}, {LogicalOpcode::SMSG_SPELLHEALLOG, 0x150}, {LogicalOpcode::SMSG_SPELLENERGIZELOG, 0x25B}, {LogicalOpcode::SMSG_PERIODICAURALOG, 0x24E},