chore(renderer): extract AnimationController and remove audio pass-throughs

Extract ~1,500 lines of character animation state from Renderer into a dedicated
AnimationController class, and complete the AudioCoordinator migration by removing
all 10 audio pass-through getters from Renderer.

AnimationController:
- New: include/rendering/animation_controller.hpp (182 lines)
- New: src/rendering/animation_controller.cpp (1,703 lines)
- Moves: locomotion state machine (50+ members), mount animation (40+ members),
  emote system, footstep triggering, surface detection, melee combat animations
- Renderer holds std::unique_ptr<AnimationController> and delegates completely
- AnimationController accesses audio via renderer_->getAudioCoordinator()

Audio caller migration:
- Migrate ~60 external callers from renderer->getXManager() to AudioCoordinator
  directly, grouped by access pattern:
  - UIServices: settings_panel, game_screen, toast_manager, chat_panel,
    combat_ui, window_manager
  - GameServices: game_handler, spell_handler, inventory_handler, quest_handler,
    social_handler, combat_handler
  - Application singleton: application.cpp, auth_screen.cpp, lua_engine.cpp
- Remove 10 pass-through getter definitions from renderer.cpp
- Remove 10 pass-through getter declarations from renderer.hpp
- Remove individual audio manager forward declarations from renderer.hpp
- Redirect 69 internal renderer.cpp audio calls to audioCoordinator_ directly
- game_handler.cpp: withSoundManager template uses services_.audioCoordinator;
  MFP changed from &Renderer::getUiSoundManager to &AudioCoordinator::getUiSoundManager
- GameServices struct: add AudioCoordinator* audioCoordinator member
- settings_panel: applyAudioVolumes(Renderer*) -> applyAudioVolumes(AudioCoordinator*)
This commit is contained in:
Paul 2026-04-02 13:06:31 +03:00
parent 5ef600098a
commit 5af9f7aa4b
22 changed files with 2208 additions and 1958 deletions

View file

@ -6,6 +6,7 @@
#include "rendering/renderer.hpp"
#include "rendering/vk_context.hpp"
#include "pipeline/asset_manager.hpp"
#include "audio/audio_coordinator.hpp"
#include "audio/music_manager.hpp"
#include "game/expansion_profile.hpp"
#include <imgui.h>
@ -199,20 +200,20 @@ void AuthScreen::render(auth::AuthHandler& authHandler) {
}
auto& app = core::Application::getInstance();
auto* renderer = app.getRenderer();
auto* ac = app.getAudioCoordinator();
if (!musicInitAttempted) {
musicInitAttempted = true;
auto* assets = app.getAssetManager();
if (renderer) {
auto* music = renderer->getMusicManager();
if (ac) {
auto* music = ac->getMusicManager();
if (music && assets && assets->isInitialized() && !music->isInitialized()) {
music->initialize(assets);
}
}
}
// Login screen music
if (renderer) {
auto* music = renderer->getMusicManager();
if (ac) {
auto* music = ac->getMusicManager();
if (music) {
if (!loginMusicVolumeAdjusted_) {
savedMusicVolume_ = music->getVolume();
@ -506,9 +507,9 @@ void AuthScreen::render(auth::AuthHandler& authHandler) {
void AuthScreen::stopLoginMusic() {
auto& app = core::Application::getInstance();
auto* renderer = app.getRenderer();
if (!renderer) return;
auto* music = renderer->getMusicManager();
auto* ac = app.getAudioCoordinator();
if (!ac) return;
auto* music = ac->getMusicManager();
if (!music) return;
if (musicPlaying) {
music->stopMusic(500.0f);

View file

@ -11,6 +11,7 @@
#include "rendering/renderer.hpp"
#include "rendering/camera.hpp"
#include "rendering/camera_controller.hpp"
#include "audio/audio_coordinator.hpp"
#include "audio/audio_engine.hpp"
#include "audio/ui_sound_manager.hpp"
#include "pipeline/asset_manager.hpp"
@ -1109,8 +1110,8 @@ void ChatPanel::render(game::GameHandler& gameHandler,
std::string bodyLower = mMsg.message;
for (auto& c : bodyLower) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
if (bodyLower.find(selfNameLower) != std::string::npos) {
if (auto* renderer = services_.renderer) {
if (auto* ui = renderer->getUiSoundManager())
if (auto* ac = services_.audioCoordinator) {
if (auto* ui = ac->getUiSoundManager())
ui->playWhisperReceived();
}
break; // play at most once per scan pass

View file

@ -15,6 +15,7 @@
#include "rendering/camera.hpp"
#include "game/game_handler.hpp"
#include "pipeline/asset_manager.hpp"
#include "audio/audio_coordinator.hpp"
#include "audio/audio_engine.hpp"
#include "audio/ui_sound_manager.hpp"
#include <imgui.h>
@ -283,9 +284,11 @@ void CombatUI::renderRaidWarningOverlay(game::GameHandler& gameHandler) {
raidWarnEntries_.erase(raidWarnEntries_.begin());
}
// Whisper audio notification
if (msg.type == game::ChatType::WHISPER && renderer) {
if (auto* ui = renderer->getUiSoundManager())
ui->playWhisperReceived();
if (msg.type == game::ChatType::WHISPER) {
if (auto* ac = services_.audioCoordinator) {
if (auto* ui = ac->getUiSoundManager())
ui->playWhisperReceived();
}
}
}
raidWarnChatSeenCount_ = newCount;

View file

@ -14,6 +14,7 @@
#include "rendering/character_renderer.hpp"
#include "rendering/camera.hpp"
#include "rendering/camera_controller.hpp"
#include "audio/audio_coordinator.hpp"
#include "audio/audio_engine.hpp"
#include "audio/music_manager.hpp"
#include "game/zone_manager.hpp"
@ -285,8 +286,8 @@ void GameScreen::render(game::GameHandler& gameHandler) {
uiErrors_.push_back({msg, 0.0f});
if (uiErrors_.size() > 5) uiErrors_.erase(uiErrors_.begin());
// Play error sound for each new error (rate-limited by deque cap of 5)
if (auto* r = services_.renderer) {
if (auto* sfx = r->getUiSoundManager()) sfx->playError();
if (auto* ac = services_.audioCoordinator) {
if (auto* sfx = ac->getUiSoundManager()) sfx->playError();
}
});
uiErrorCallbackSet_ = true;
@ -345,9 +346,9 @@ void GameScreen::render(game::GameHandler& gameHandler) {
// Apply saved volume settings once when audio managers first become available
if (!settingsPanel_.volumeSettingsApplied_) {
auto* renderer = services_.renderer;
if (renderer && renderer->getUiSoundManager()) {
settingsPanel_.applyAudioVolumes(renderer);
auto* ac = services_.audioCoordinator;
if (ac && ac->getUiSoundManager()) {
settingsPanel_.applyAudioVolumes(ac);
settingsPanel_.volumeSettingsApplied_ = true;
}
}
@ -6525,38 +6526,38 @@ void GameScreen::renderMinimapMarkers(game::GameHandler& gameHandler) {
}
auto applyMuteState = [&]() {
auto* activeRenderer = services_.renderer;
auto* ac = services_.audioCoordinator;
float masterScale = settingsPanel_.soundMuted_ ? 0.0f : static_cast<float>(settingsPanel_.pendingMasterVolume) / 100.0f;
audio::AudioEngine::instance().setMasterVolume(masterScale);
if (!activeRenderer) return;
if (auto* music = activeRenderer->getMusicManager()) {
if (!ac) return;
if (auto* music = ac->getMusicManager()) {
music->setVolume(settingsPanel_.pendingMusicVolume);
}
if (auto* ambient = activeRenderer->getAmbientSoundManager()) {
if (auto* ambient = ac->getAmbientSoundManager()) {
ambient->setVolumeScale(settingsPanel_.pendingAmbientVolume / 100.0f);
}
if (auto* ui = activeRenderer->getUiSoundManager()) {
if (auto* ui = ac->getUiSoundManager()) {
ui->setVolumeScale(settingsPanel_.pendingUiVolume / 100.0f);
}
if (auto* combat = activeRenderer->getCombatSoundManager()) {
if (auto* combat = ac->getCombatSoundManager()) {
combat->setVolumeScale(settingsPanel_.pendingCombatVolume / 100.0f);
}
if (auto* spell = activeRenderer->getSpellSoundManager()) {
if (auto* spell = ac->getSpellSoundManager()) {
spell->setVolumeScale(settingsPanel_.pendingSpellVolume / 100.0f);
}
if (auto* movement = activeRenderer->getMovementSoundManager()) {
if (auto* movement = ac->getMovementSoundManager()) {
movement->setVolumeScale(settingsPanel_.pendingMovementVolume / 100.0f);
}
if (auto* footstep = activeRenderer->getFootstepManager()) {
if (auto* footstep = ac->getFootstepManager()) {
footstep->setVolumeScale(settingsPanel_.pendingFootstepVolume / 100.0f);
}
if (auto* npcVoice = activeRenderer->getNpcVoiceManager()) {
if (auto* npcVoice = ac->getNpcVoiceManager()) {
npcVoice->setVolumeScale(settingsPanel_.pendingNpcVoiceVolume / 100.0f);
}
if (auto* mount = activeRenderer->getMountSoundManager()) {
if (auto* mount = ac->getMountSoundManager()) {
mount->setVolumeScale(settingsPanel_.pendingMountVolume / 100.0f);
}
if (auto* activity = activeRenderer->getActivitySoundManager()) {
if (auto* activity = ac->getActivitySoundManager()) {
activity->setVolumeScale(settingsPanel_.pendingActivityVolume / 100.0f);
}
};

View file

@ -17,6 +17,7 @@
#include "rendering/wmo_renderer.hpp"
#include "rendering/character_renderer.hpp"
#include "game/zone_manager.hpp"
#include "audio/audio_coordinator.hpp"
#include "audio/audio_engine.hpp"
#include "audio/music_manager.hpp"
#include "audio/ambient_sound_manager.hpp"
@ -439,7 +440,7 @@ ImGui::BeginChild("AudioSettings", ImVec2(0, 360), true);
// Helper lambda to apply audio settings
auto applyAudioSettings = [&]() {
applyAudioVolumes(renderer);
applyAudioVolumes(services_.audioCoordinator);
saveCallback();
};
@ -1227,29 +1228,29 @@ std::string SettingsPanel::getSettingsPath() {
return dir + "/settings.cfg";
}
void SettingsPanel::applyAudioVolumes(rendering::Renderer* renderer) {
if (!renderer) return;
void SettingsPanel::applyAudioVolumes(audio::AudioCoordinator* ac) {
if (!ac) return;
float masterScale = soundMuted_ ? 0.0f : static_cast<float>(pendingMasterVolume) / 100.0f;
audio::AudioEngine::instance().setMasterVolume(masterScale);
if (auto* music = renderer->getMusicManager())
if (auto* music = ac->getMusicManager())
music->setVolume(pendingMusicVolume);
if (auto* ambient = renderer->getAmbientSoundManager())
if (auto* ambient = ac->getAmbientSoundManager())
ambient->setVolumeScale(pendingAmbientVolume / 100.0f);
if (auto* ui = renderer->getUiSoundManager())
if (auto* ui = ac->getUiSoundManager())
ui->setVolumeScale(pendingUiVolume / 100.0f);
if (auto* combat = renderer->getCombatSoundManager())
if (auto* combat = ac->getCombatSoundManager())
combat->setVolumeScale(pendingCombatVolume / 100.0f);
if (auto* spell = renderer->getSpellSoundManager())
if (auto* spell = ac->getSpellSoundManager())
spell->setVolumeScale(pendingSpellVolume / 100.0f);
if (auto* movement = renderer->getMovementSoundManager())
if (auto* movement = ac->getMovementSoundManager())
movement->setVolumeScale(pendingMovementVolume / 100.0f);
if (auto* footstep = renderer->getFootstepManager())
if (auto* footstep = ac->getFootstepManager())
footstep->setVolumeScale(pendingFootstepVolume / 100.0f);
if (auto* npcVoice = renderer->getNpcVoiceManager())
if (auto* npcVoice = ac->getNpcVoiceManager())
npcVoice->setVolumeScale(pendingNpcVoiceVolume / 100.0f);
if (auto* mount = renderer->getMountSoundManager())
if (auto* mount = ac->getMountSoundManager())
mount->setVolumeScale(pendingMountVolume / 100.0f);
if (auto* activity = renderer->getActivitySoundManager())
if (auto* activity = ac->getActivitySoundManager())
activity->setVolumeScale(pendingActivityVolume / 100.0f);
}

View file

@ -2,6 +2,7 @@
#include "game/game_handler.hpp"
#include "core/application.hpp"
#include "rendering/renderer.hpp"
#include "audio/audio_coordinator.hpp"
#include "audio/ui_sound_manager.hpp"
#include <imgui.h>
@ -461,11 +462,13 @@ void ToastManager::triggerDing(uint32_t newLevel, uint32_t hpDelta, uint32_t man
dingStats_[3] = intel;
dingStats_[4] = spi;
auto* renderer = services_.renderer;
if (renderer) {
if (auto* sfx = renderer->getUiSoundManager()) {
auto* ac = services_.audioCoordinator;
if (ac) {
if (auto* sfx = ac->getUiSoundManager()) {
sfx->playLevelUp();
}
}
if (auto* renderer = services_.renderer) {
renderer->playEmote("cheer");
}
}
@ -550,9 +553,9 @@ void ToastManager::triggerAchievementToast(uint32_t achievementId, std::string n
achievementToastTimer_ = ACHIEVEMENT_TOAST_DURATION;
// Play a UI sound if available
auto* renderer = services_.renderer;
if (renderer) {
if (auto* sfx = renderer->getUiSoundManager()) {
auto* ac = services_.audioCoordinator;
if (ac) {
if (auto* sfx = ac->getUiSoundManager()) {
sfx->playAchievementAlert();
}
}

View file

@ -16,6 +16,7 @@
#include "game/game_handler.hpp"
#include "pipeline/asset_manager.hpp"
#include "pipeline/dbc_layout.hpp"
#include "audio/audio_coordinator.hpp"
#include "audio/ui_sound_manager.hpp"
#include "audio/music_manager.hpp"
#include <imgui.h>
@ -1701,9 +1702,9 @@ void WindowManager::renderEscapeMenu(SettingsPanel& settingsPanel) {
settingsPanel.showEscapeSettingsNotice = false;
}
if (ImGui::Button("Quit", ImVec2(-1, 0))) {
auto* renderer = services_.renderer;
if (renderer) {
if (auto* music = renderer->getMusicManager()) {
auto* ac = services_.audioCoordinator;
if (ac) {
if (auto* music = ac->getMusicManager()) {
music->stopMusic(0.0f);
}
}