From 97192ab2a419fa1aceae34dc9aad47dd7a6c3c6a Mon Sep 17 00:00:00 2001 From: Kelsi Date: Mon, 9 Mar 2026 16:16:39 -0700 Subject: [PATCH] Upgrade SMSG_PLAY_OBJECT_SOUND/SPELL_IMPACT to 3D positional audio Add PlayPositionalSoundCallback that carries both soundId and sourceGuid. In Application, look up the source entity position and play via AudioEngine::playSound3D(); fall back to playSound2D() when the entity is unknown. Also read the 8-byte sourceGuid field from the packet (previously the full 12-byte payload was ignored). --- include/game/game_handler.hpp | 6 ++++++ src/core/application.cpp | 29 +++++++++++++++++++++++++++++ src/game/game_handler.cpp | 10 ++++++++-- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/include/game/game_handler.hpp b/include/game/game_handler.hpp index 3534acf6..56f4bae1 100644 --- a/include/game/game_handler.hpp +++ b/include/game/game_handler.hpp @@ -948,6 +948,11 @@ public: using PlaySoundCallback = std::function; void setPlaySoundCallback(PlaySoundCallback cb) { playSoundCallback_ = std::move(cb); } + // Server-triggered 3-D positional sound callback — fires for SMSG_PLAY_OBJECT_SOUND and + // SMSG_PLAY_SPELL_IMPACT. Includes sourceGuid so the receiver can look up world position. + using PlayPositionalSoundCallback = std::function; + void setPlayPositionalSoundCallback(PlayPositionalSoundCallback cb) { playPositionalSoundCallback_ = std::move(cb); } + // Mount state using MountCallback = std::function; // 0 = dismount void setMountCallback(MountCallback cb) { mountCallback_ = std::move(cb); } @@ -2103,6 +2108,7 @@ private: // ---- Server-triggered audio ---- PlayMusicCallback playMusicCallback_; PlaySoundCallback playSoundCallback_; + PlayPositionalSoundCallback playPositionalSoundCallback_; }; } // namespace game diff --git a/src/core/application.cpp b/src/core/application.cpp index e6199c7a..e07b4130 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -2142,6 +2142,35 @@ void Application::setupUICallbacks() { } }); + // SMSG_PLAY_OBJECT_SOUND / SMSG_PLAY_SPELL_IMPACT: play as 3D positional sound at source entity + gameHandler->setPlayPositionalSoundCallback([this](uint32_t soundId, uint64_t sourceGuid) { + if (!assetManager || !gameHandler) return; + + auto dbc = assetManager->loadDBC("SoundEntries.dbc"); + if (!dbc || !dbc->isLoaded()) return; + + int32_t idx = dbc->findRecordById(soundId); + if (idx < 0) return; + + const uint32_t row = static_cast(idx); + std::string dir = dbc->getString(row, 23); + for (uint32_t f = 3; f <= 12; ++f) { + std::string name = dbc->getString(row, f); + if (name.empty()) continue; + std::string path = dir.empty() ? name : dir + "\\" + name; + + // Play as 3D sound if source entity position is available + auto entity = gameHandler->getEntityManager().getEntity(sourceGuid); + if (entity) { + glm::vec3 pos{entity->getLatestX(), entity->getLatestY(), entity->getLatestZ()}; + audio::AudioEngine::instance().playSound3D(path, pos); + } else { + audio::AudioEngine::instance().playSound2D(path); + } + return; + } + }); + // Other player level-up callback — trigger 3D effect + chat notification gameHandler->setOtherPlayerLevelUpCallback([this](uint64_t guid, uint32_t newLevel) { if (!gameHandler || !renderer) return; diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 6eab2fb5..1e44b6bb 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -4507,9 +4507,15 @@ void GameHandler::handlePacket(network::Packet& packet) { // ---- Play object/spell sounds ---- case Opcode::SMSG_PLAY_OBJECT_SOUND: case Opcode::SMSG_PLAY_SPELL_IMPACT: - if (packet.getSize() - packet.getReadPos() >= 4) { + if (packet.getSize() - packet.getReadPos() >= 12) { + // uint32 soundId + uint64 sourceGuid + uint32_t soundId = packet.readUInt32(); + uint64_t srcGuid = packet.readUInt64(); + LOG_DEBUG("SMSG_PLAY_OBJECT_SOUND/SPELL_IMPACT id=", soundId, " src=0x", std::hex, srcGuid, std::dec); + if (playPositionalSoundCallback_) playPositionalSoundCallback_(soundId, srcGuid); + else if (playSoundCallback_) playSoundCallback_(soundId); + } else if (packet.getSize() - packet.getReadPos() >= 4) { uint32_t soundId = packet.readUInt32(); - LOG_DEBUG("SMSG_PLAY_OBJECT_SOUND/SPELL_IMPACT id=", soundId); if (playSoundCallback_) playSoundCallback_(soundId); } packet.setReadPos(packet.getSize());